【Unity/XLua】xlua自带教程示例分析(四)—— 使用C#接口和委托获取lua定义的表和对应特殊方法

第一步 创建Lua脚本

元表部分

lua 复制代码
lualocal calc_mt = {
    __index = {
        Add = function(self, a, b)
            return (a + b) * self.Mult
        end,
        
        get_Item = function(self, index)
            return self.list[index + 1]
        end,

        set_Item = function(self, index, value)
            self.list[index + 1] = value
            self:notify({name = index, value = value})
        end,
        
        add_PropertyChanged = function(self, delegate)
            if self.notifylist == nil then
                self.notifylist = {}
            end
            table.insert(self.notifylist, delegate)
            print('add', delegate)
        end,
                                
        remove_PropertyChanged = function(self, delegate)
            for i=1, #self.notifylist do
                if CS.System.Object.Equals(self.notifylist[i], delegate) then
                    table.remove(self.notifylist, i)
                    break
                end
            end
            print('remove', delegate)
        end,

        notify = function(self, evt)
            if self.notifylist ~= nil then
                for i=1, #self.notifylist do
                    self.notifylist[i](self, evt)
                end
            end	
        end,
    }
}
  • __index字段定义了元表的索引,即当通过实例访问一个字段或方法时,如果该实例本身没有这个字段或方法,Lua会查找元表中的__index来获取。
  • Add(self, a, b): 这是一个方法,接受两个参数 ab,返回它们相加后乘以实例的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传递给它们。

表部分

lua 复制代码
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的表结构对应的接口

cs 复制代码
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执行过程操作

cs 复制代码
void Test(LuaEnv luaenv)
{
    luaenv.DoString(script);
    CalcNew calc_new = luaenv.Global.GetInPath<CalcNew>("Calc.New");
    ICalc calc = calc_new(10, "hi", "john"); //constructor
    Debug.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#中使用[]运算符重载时调用,算是一种命名规范

相关推荐
两水先木示4 小时前
【Unity3D】微信小游戏适配安全区域或胶囊控件(圆圈按钮)水平高度一致方案
unity·微信小游戏·安全区域·ui适配·胶囊控件·safearea
枯萎穿心攻击5 小时前
ECS由浅入深第三节:进阶?System 的行为与复杂交互模式
开发语言·unity·c#·游戏引擎
小码编匠5 小时前
WPF 自定义TextBox带水印控件,可设置圆角
后端·c#·.net
水果里面有苹果5 小时前
17-C#的socket通信TCP-1
开发语言·tcp/ip·c#
不绝1915 小时前
怪物机制分析(有限状态机、编辑器可视化、巡逻机制)
网络·游戏·unity·游戏引擎
unicrom_深圳市由你创科技6 小时前
Unity开发如何解决iOS闪退问题
unity·ios·蓝桥杯
Yasin Chen11 小时前
C# Dictionary源码分析
算法·unity·哈希算法
阿蒙Amon13 小时前
C# Linq to SQL:数据库编程的解决方案
数据库·c#·linq
iCxhust15 小时前
c# U盘映像生成工具
开发语言·单片机·c#
emplace_back17 小时前
C# 集合表达式和展开运算符 (..) 详解
开发语言·windows·c#