第一步 创建Lua脚本
元表部分
lualocal calc_mt = {__index = {Add = function(self, a, b)return (a + b) * self.Multend,get_Item = function(self, index)return self.list[index + 1]end,set_Item = function(self, index, value)self.list[index + 1] = valueself:notify({name = index, value = value})end,add_PropertyChanged = function(self, delegate)if self.notifylist == nil thenself.notifylist = {}endtable.insert(self.notifylist, delegate)print('add', delegate)end,remove_PropertyChanged = function(self, delegate)for i=1, #self.notifylist doif CS.System.Object.Equals(self.notifylist[i], delegate) thentable.remove(self.notifylist, i)breakendendprint('remove', delegate)end,notify = function(self, evt)if self.notifylist ~= nil thenfor i=1, #self.notifylist doself.notifylist[i](self, evt)endend end,}
}
__index
字段定义了元表的索引,即当通过实例访问一个字段或方法时,如果该实例本身没有这个字段或方法,Lua会查找元表中的__index
来获取。Add(self, a, b)
: 这是一个方法,接受两个参数a
和b
,返回它们相加后乘以实例的Mult
字段的结果。get_Item(self, index)
: 这个方法通过索引访问self.list
表中的元素,索引从1开始。set_Item(self, index, value)
: 这个方法用于设置self.list
表中特定索引的值,并调用notify
方法通知任何监听属性变化的回调函数。add_PropertyChanged(self, delegate)
: 这个方法用于向notifylist
中添加属性变化监听的回调函数。remove_PropertyChanged(self, delegate)
: 这个方法用于从notifylist
中移除指定的属性变化监听回调函数。notify(self, evt)
: 这个方法用于触发notifylist
中所有回调函数,并将事件对象evt
传递给它们。
表部分
luaCalc = {New = function (mult, ...)print(...)return setmetatable({Mult = mult, list = {'aaaa','bbbb','cccc'}}, calc_mt)end
}
-
Calc
表定义了一个方法New
,这个方法接受一个参数mult
和可变数量的其他参数)。方法返回了一个使用 calc_mt 作为元表的表。这个表包含两个字段:
Mult
:传递给New
方法的参数mult
。list
:一个包含三个字符串的数组。
第二步 创建C#脚本
首先声明与Lua的表结构对应的接口
public class PropertyChangedEventArgs : EventArgs
{public string name;public object value;
}[CSharpCallLua]
public interface ICalc
{event EventHandler<PropertyChangedEventArgs> PropertyChanged;int Add(int a, int b);int Mult { get; set; }object this[int index] { get; set; }
}[CSharpCallLua]
public delegate ICalc CalcNew(int mult, params string[] args);
首先是打头的PropertyChangedEventArgs,这是一个C#中和EventHandler配合使用的EventArgs类,用于表示参数
在lua中,其对应了set_item中的 self:notify({name = index, value = value}) 中输入的参数
其次是ICalc接口,该接口对应了luaCalc的返回值,其既声明了calc_mt元表中的字段,又声明了如Mult这个在luaCalc的New方法中才声明的字段。ICalc还重写了[]运算符
最后是委托方法,该方法对应了luaCalc的New函数,输入的参数一样,使用ICalc接口来接收对应值
接口和CalcNew方法都要打上CSharpCallLua标签,因为我们想要在C#中去访问和接收lua函数和返回值
第三步 lua执行过程操作
void Test(LuaEnv luaenv)
{luaenv.DoString(script);CalcNew calc_new = luaenv.Global.GetInPath<CalcNew>("Calc.New");ICalc calc = calc_new(10, "hi", "john"); //constructorDebug.Log("sum(*10) =" + calc.Add(1, 2));calc.Mult = 100;Debug.Log("sum(*100)=" + calc.Add(1, 2));Debug.Log("list[0]=" + calc[0]);Debug.Log("list[1]=" + calc[1]);calc.PropertyChanged += Notify;calc[1] = "dddd";Debug.Log("list[1]=" + calc[1]);calc.PropertyChanged -= Notify;calc[1] = "eeee";Debug.Log("list[1]=" + calc[1]);
}void Notify(object sender, PropertyChangedEventArgs e)
{Debug.Log(string.Format("{0} has property changed {1}={2}", sender, e.name, e.value));
}
首先先使用DoString在环境中执行对应脚本,将其表都加载进虚拟机
接着创建一个声明了的委托对象calc_new接收Calc.New函数
再调用这个函数,并使用ICalc来接收构造好的表
接着便可以访问内部的对应函数和变量,如Add,Mult
值得注意的是在lua中声明的add_PropertyChanged,remove_PropertyChanged
在C#定义的接口中即会在事件PropertyChanged的 += 和 -= 时触发
其次是get_Item和set_Item,也会在C#中使用[]运算符重载时调用,算是一种命名规范