Xlua
C#调用Lua
lua解析器
lua解析器可以让我们在unity中执行Lua,一般情况下,我们会保证它在unity中的唯一性。
//创建一个lua解析器
LuaEnv env = new LuaEnv();
//执行Lua语言
env.DoString("print('你好世界')");
//像上面这样一句一句的执行lua脚本是非常不好的,所以可以使用lua脚本加载的知识来解决这个问题。
//xlua默认的脚本寻找路径是在Resources文件夹中,但是由于unity并不能识别Lua文件,所以直接加载时会报错的。解决方案是我们将lua后缀多加一个txt,将其转换为文本文件。
env.DoString("require('Main')");
//此方法可以帮助我们清除Lua中我们没有手动释放的对象,相当于垃圾回收。
//我们可以在帧更新中定时执行,也可以在切换场景时执行。
env.Tick();
//销毁Lua解析器,一般会用的会比较少,因为我们之前说过了,我们基本会保证Lua解析器在unity中是全局唯一的。
env.Dispose();
lua文件重定向
//需要调用此方法来添加新的路径,参数为委托类型
//delegate byte[] CustomLoader(ref string filepath)
env.AddLoader(NewLoader);
//这里我们写一个方法并传进去
private byte[] NewLoader(ref string filepath)
{
//路径拼接需要加上后缀
string path = Application.dataPath + "/Lua/" + filepath + ".lua";
if (File.Exists(path))
{
return File.ReadAllBytes(path);
}
return null;
}
//由于委托可以注册多个方法,所以xlua的文件重定向查找方案也是优先查找委托中所有的路径,最后查找默认路径Resources。
//一旦找到对应文件就会返回。不再继续
获取全局变量
//首先我们需要编辑一个test.lua脚本并书写一下信息
print("Test脚本");
testNumber = 1;
testBool = true;
testFloat = 1.2;
testString = "你好";
//在之前的LuaManager中我们添加了一个Global属性,用于获得lua解析器的_G表。
//我们调用xlua的Global中的get方法来获取lua解析器读取的lua脚本中_G表所存放的全局变量。
//注意,字符串内容需要与lua中的变量名一致。
//这里是值拷贝,就算使用临时变量接受了返回值并进行改变也不会影响Lua脚本中的值。
print(LuaManager.GetInstance.Global.Get<int>("testNumber"));
print(LuaManager.GetInstance.Global.Get<bool>("testBool"));
//虽然lua只有一种数值类型number,但是我们可以根据其内容来在C#中为其赋予类型
print(LuaManager.GetInstance.Global.Get<float>("testFloat"));
print(LuaManager.GetInstance.Global.Get<string>("testString"));
//想要改变Lua脚本中的值,我们需要使用Global提供给我们的Set方法。
LuaManager.GetInstance.Global.Set("testNumber",5);
print(LuaManager.GetInstance.Global.Get<int>("testNumber"));
获得全局函数
//我们在test.lua中添加新成员
testFunc1 = function()
print("这是一个无参无返回值的函数");
end
testFunc2 = function(param)
print("这是一个有参有返回值的函数");
return param + 1;
end
testFunc3 = function()
print("这是一个多返回值的函数");
return 1,2,"123";
end
testFunc4 = function(...)
arg = {...};
print("这是一个有变长参数的函数");
for k,v in pairs(arg) do
print(k,v)
end
end
//总的来说,获得lua的全局函数需要使用到委托。
//这里我们可以使用自定义委托,C#提供的标准委托,或是使用Xlua提供的委托。
//注意使用Xlua提供的委托可能发生拆箱装箱
//我们先来看第一种情况,无参无返回值,我们直接使用Action委托来接受。
Action func1 = LuaManager.GetInstance.Global.Get<Action>("testFunc1");
func1.Invoke();
//第二种情况,有参有返回值,我们直接使用Func委托来接受。
Func<int, int> func2 = LuaManager.GetInstance.Global.Get<Func<int, int>>("testFunc2");
func2.Invoke(10);
//第三种情况,多返回值的函数,我们需要自定义委托来接受。首先我们自定义委托
//当我们要使用自定义委托来接受lua中的全局函数时,我们需要为委托添加[CSharpCallLua]特性,并重新加载。
[CSharpCallLua]
public delegate void FuncHandler(out int paramA,out int paramB, out string paramC);
//使用此委托接受
FuncHandler func3 = LuaManager.GetInstance.Global.Get<FuncHandler>("testFunc3");
int paramA;
int paramB;
string paramC;
func3.Invoke(out paramA,out paramB,out paramC);
//第四种情况,要求输入一个变长参数,我们依旧需要自定义委托来接受。
[CSharpCallLua]
public delegate void FuncHandler2(params object[] array);
FuncHandler2 func4 = LuaManager.GetInstance.Global.Get<FuncHandler2>("testFunc4");
func4.Invoke(1,2,3,"qwe",true);
List,Dictionary映射Table
//使用List和Dictionary映射Table和之前说过的获得全局变量是一样的。
//来到lua脚本我们添加一些表
testList1 = {1,2,3,4,5,6};
testList2 = {1,2,3,"123",true,false};
testDic1 = {
["1"] = 1,
["2"] = 2,
["3"] = 3,
["4"] = 4,
}
testDic2 = {
["1"] = 1,
["2"] = 2,
["3"] = true,
["4"] = false,
}
//来到C#使用list或者dictionary直接接受
//注意这里的接受依旧是值拷贝
List<int> testList1 = LuaManager.GetInstance.Global.Get<List<int>>("testList1");
foreach (var item in testList1)
{
print(item);
}
List<object> testList2 = LuaManager.GetInstance.Global.Get<List<object>>("testList2");
foreach (var item in testList2)
{
print(item);
}
Dictionary<string, int> testDic1 = LuaManager.GetInstance.Global.Get<Dictionary<string, int>>("testDic1");
foreach (var key in testDic1.Keys)
{
print($"{key}_{testDic1[key]}");
}
Dictionary<string, object> testDic2 = LuaManager.GetInstance.Global.Get<Dictionary<string, object>>("testDic2");
foreach (var key in testDic2.Keys)
{
print($"{key}_{testDic2[key]}");
}
类映射Table
//使用C#类映射lua中的类表
//首先我们先在lua中写一个类表,其中包含number类型,string类型,boolean类型和function类型
testClass = {
myInt = 1,
myString = "你好",
myBool = true,
myFunc = function()
print("testClass的函数");
end
}
//接下来我们来书写C#中准备接受这个表的类
//其中,类名实没有要求的,但是在这个类中声明的成员变量名称需要和lua中的名称一致,这也是首次要求名称对应。
//类的成员变量需要是公共的,或者internal,其他类型将无法赋值。
//我们不需要将lua中声明的类型在这里全部声明;不论是多出来的变量还是缺少的变量,Xlua都会选择忽略。
public class CallLuaClass
{
public int myInt;
public string myString;
public bool myBool;
public Action myFunc;
}
//使用类映射table依旧是值拷贝
接口映射Table
接口映射Table和类大同小异,但在使用时需要注意:
- 接口需要统一使用属性来接受lua脚本中的成员。
- 使用接口映射Table时,需要和自定义委托一样加上特性并重新编译。
- 如果改变了接口的内容,一定要先清除在编译。
- 接口是引用拷贝,改变接口的值,lua中的值也会改变。
LuaTable,LuaFunction
首先要说的是,官方不推荐使用luaTable接收lua中的Table,也不推荐使用LuaFunction接收Lua中的function,他们执行效率低,且需要手动释放资源。
但需要注意的是。LuaTable和LuaFunction是引用拷贝,可以通过set方法改变lua脚本中的值。
*Lua调用C#
Lua使用C#类
print("*********Lua调用C#类相关知识点*********");
--对于lua调用C#的方法,我们一定是通过C#先进入Lua的
--通过DoString方法进入
--lua中使用C#的类非常简单
--固定套路
--CS.命名空间.类名
--Unity的类 比如 GameObject , Transform等等 可以通过CS.UnityEngine.类名进行调用
--CS.UnityEngine.GameObject
--CS.UnityEngine.Transform
print("通过C#中的类在Lua中实例化一个游戏对象");
--由于Lua中没有new,所以在Lua中我们有另外的语法来创建对象。
--在Lua中类名括号就是在实例化对象,默认的调用的相当于就是无参构造函数。
--调用无参构造函数
local gameObject1 = CS.UnityEngine.GameObject();
--调用有参构造函数
local gameObject2 = CS.UnityEngine.GameObject("有参构造函数对象");
--为了方便使用并节约性能,定义全局变量存储C#中的类
--相当于取了一个别名
GameObject = CS.UnityEngine.GameObject;
local gameObject3 = GameObject("这是一个取了别名的游戏对象");
--类中的静态对象可以直接使用.运算符来调用
local gameObject4 = GameObject.Find("这是一个取了别名的游戏对象");
--得到对象中的成员变量,直接使用.运算符即可
print(gameObject4.transform.position);
Debug = CS.UnityEngine.Debug;
Debug.Log(gameObject4.transform.position);
--如果使用对象中的成员方法一定要使用:
Vector3 = CS.UnityEngine.Vector3;
gameObject4.transform:Translate(Vector3.right);
Debug.Log(gameObject4.transform.position);
--使用不继承Mono的普通类,首先在C#中创建一个Test类
Test = CS.Test;
--创建一个对象
local test = Test();
test:Speak("123");
--继承Mono的类。
--注意继承Mono的类是不可以直接new的,我们需要使用AddComponent方法
local gameObject5 = GameObject("加脚本测试");
--通过GameObject的AddComponent添加脚本
--Xlua提供了一个重要的方法typeof可以获得类的Type
--Xlua中不支持无参泛型函数,所以我们需要使用AddComponent的另一个重载
gameObject5:AddComponent(typeof(CS.Test1_LuaEnv));
Lua使用C#枚举
print("*********Lua调用C#枚举相关知识点*********");
--Lua调用C#的枚举,和调用C#的类相似,直接使用.运算符来使用其枚举值
--调用Unity中的默认枚举
--首先参照lua调用类,我们先将枚举的命名空间保存
PrimitiveType = CS.UnityEngine.PrimitiveType;
GameObject = CS.UnityEngine.GameObject;
--unity中创建默认几何体的代码
local obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
--自定义枚举,使用方法和unity的默认枚举一样,但需要注意命名空间
--我们联合枚举转换一起来说
E_MyEnum = CS.E_MyEnum;
print(E_MyEnum.idle);
--数值转枚举
local enum1 = E_MyEnum.__CastFrom(1);
print(enum1);
--字符串转枚举
local enum2 = E_MyEnum.__CastFrom("atk");
print(enum2);
Lua使用C#数组,List,Dictionary
print("*********Lua调用C#数组相关知识点*********");
--需要注意,虽然我们在Lua中使用表来模拟数组,list,dictionary,但是当lua调用C#时,我们要遵守C#的使用规则。
--首先我们现在Lua中创建一个C#的数组
--这里我们调用C#中Array基类的CreateInstance方法来创建,具体参数信息需要查阅C#
--这里我们使用的方法第一个参数传入type,第二个参数传入容量
local array = CS.System.Array.CreateInstance(typeof(CS.System.Int32),10);
--获得数组的长度,这里调用了C#中的成员变量
print(array.Length);
--访问数组的元素
print(array[0]);
--数组遍历,这里需要注意,虽然Lua的索引是从1开始,但是我们使用的是C#的数组,其索引是从0开始的。
--注意Lua中的for循环遍历一定要减1
for i=1,array.Length - 1 do
print(array[i]);
end
print("*********Lua调用C#List相关知识点*********");
--首先我们还是先创建一个List对象,这里有两种方式。
--老版本
--其中CS.System.Collections.Generic是List泛型的命名空间,List`1指的是此泛型有一个泛型参数。
local list = CS.System.Collections.Generic["List`1[System.String]"]();
list:Add("5555");
print(list[0]);
--新版本
local List_String = CS.System.Collections.Generic.List(CS.System.String);
local list2 = List_String();
list2:Add("123");
print(list2[0]);
--输出长度
print(list2.Count);
print("*********Lua调用C#Dictionary相关知识点*********");
--我们还是先来创建一个字典
local dictionary_Int_Vector3 = CS.System.Collections.Generic.Dictionary(CS.System.String, CS.UnityEngine.Vector3);
local dic = dictionary_Int_Vector3();
dic:Add("123",CS.UnityEngine.Vector3.right);
--除了int类型的键,其他无法通过索引直接获得,这里会直接报空
print(dic["123"]);
--我们通过以下方法来获得键值
--1. TryGetValue
print(dic:TryGetValue("123"));
--2. get_Item, set_Item
print(dic:get_Item("123"));
dic:set_Item("123",nil);
print(dic:get_Item("123"));
Lua使用C#拓展方法
print("*********Lua调用C#List相关知识点*********");
local ExMethodDemo = CS.ExMethodDemo();
--Lua调用C#的拓展方法时,需要在拓展方法的类上面加上[LuacallCSharp]这个特性,并重新加载
--使用拓展方法和使用成员方法一样使用:,毕竟拓展方法本身就是将自己作为参数传进去了。
ExMethodDemo:Eat();
--[[
总结:
1. 想要在Lua中使用拓展方法,就一定要加上[LuacallCSharp]特性。
2. 建议Lua中要使用的C#类都使用这个特性,可以提升性能。
3. Xlua是通过反射来调用C#类的,当我们加了上述特性并重新加载代码后,相当于提前做了工作。
]]
Lua使用ref和out
print("*********Lua调用C#ref和out相关知识点*********");
local RefAndOut = CS.RefAndOut();
--C#中的ref参数会以多返回值的形式返回给Lua。
--如果函数存在返回值,则第一个默认返回该返回值。
--之后返回的结果就是ref的结果,从左到右一一对应。
--ref参数需要传入一个默认值来占位,这点和C#中使用是非常相似的。
local paramA,paramB,paramC = RefAndOut:RefTest(1,0,0,1);
print(paramA);
print(paramB);
print(paramC);
--C#中的out参数会以多返回值的形式返回给Lua。
--如果函数存在返回值,则第一个默认返回该返回值。
--之后返回的结果就是out的结果,从左到右一一对应。
--与ref不同,out参数不需要占位,当然如果你传入参数也没有事。
local paramA,paramB,paramC = RefAndOut:OutTest(2,1);
print(paramA);
print(paramB);
print(paramC);
--ref和out的综合使用,总体区别在于ref需要占位,out不需要
local paramA,paramB,paramC = RefAndOut:RefOut(2,1,1,1);
print(paramA);
print(paramB);
print(paramC);
Lua使用C#重载方法
print("*********Lua调用C#重载方法相关知识点*********");
--虽然lua自己不支持重载函数的书写,但是可以调用C#中的重载函数
--原因是lua中对于相同变量的函数赋值会覆盖之前赋值的函数,所以不能重载函数是,但如果调用C#的话很明显就不会存在这个问题。
local CallOverrideFunc = CS.LuaCallOverride();
CallOverrideFunc:CallOverrideWithParam();
--注意,由于lua中在数值类型上只支持number类型,所以对于C#中参数个数相同,数值精度不同的重载无法正确获得。
--我们要尽量避免这种写法,或者使用Xlua提供给我们的反射解决方案。
--需要注意的是,此方案毕竟是通过反射实现的,性能较差,不到万不得已的情况下不要使用。
print(CallOverrideFunc:CallOverrideWithParam(10));
print(CallOverrideFunc:CallOverrideWithParam(10.2));
--反射解决方案
--首先通过反射获得需要使用的方法
local method1 = typeof(CS.LuaCallOverride):GetMethod("CallOverrideWithParam", {typeof(CS.System.Int32)});
local method2 = typeof(CS.LuaCallOverride):GetMethod("CallOverrideWithParam", {typeof(CS.System.Single)});
--通过Xlua提供的tofunction方法转换为lua函数
--一般我们只转换一次,之后重复使用
local luafunc1 = xlua.tofunction(method1);
local luafunc2 = xlua.tofunction(method2);
--转换完成后,需要注意:
--如果目标方法为成员方法,则第一个参数需要传调用对象。
--如果目标方法为静态方法,则不需要。
print(luafunc1(CallOverrideFunc,10));
print(luafunc2(CallOverrideFunc,10.2));
Lua使用C#委托事件
print("*********Lua调用C#委托事件相关知识点*********");
--Lua使用C#委托事件的语法基本上和C#中的使用是一致的。
local LuaCallDelegate = CS.LuaCallDelegate();
local func1 = function()
print("Lua使用c#委托调用lua的方法");
end
--Lua中使用C#委托,将其当作成员变量来使用,使用的规则和C#中一样,先等号赋值,再+=
--需要注意,lua中没有+=运算,需要我们老老实实的写A = A + B这种形式。
LuaCallDelegate.DelegateTest = func1;
--lua中使用C#委托,也可以直接添加lua函数,这种添加方法有点类似于在C#中添加匿名方法或者lambda表达式。
--不建议使用,因为这种添加形式只能加不能减。
LuaCallDelegate.DelegateTest = LuaCallDelegate.DelegateTest + function()
print("lua使用C#委托添加的临时变量");
end
LuaCallDelegate.DelegateTest();
--注销回调函数
LuaCallDelegate.DelegateTest = LuaCallDelegate.DelegateTest - func1;
LuaCallDelegate.DelegateTest();
--清空委托链,相当于C#中调用 = null
LuaCallDelegate.DelegateTest = nil;
local func2 = function()
print("事件添加的函数");
end
--在事件的添加上,lua不同于C#
--事件添加函数使用对象名:事件名("+",函数名)的方式来添加
--注销事件同理
LuaCallDelegate:EventTest("+",func2);
LuaCallDelegate:OnEventStart();
--同样可以使用此方法来添加匿名函数
LuaCallDelegate:EventTest("+",function()
print("这是使用事件添加的匿名函数");
end
);
LuaCallDelegate:OnEventStart();
--注销事件
LuaCallDelegate:EventTest("-",func2);
LuaCallDelegate:OnEventStart();
--由于事件不能在类外调用委托链清空,所以我们将委托链清空的方法封装在事件申明类中。
LuaCallDelegate:ClearEvent();
LuaCallDelegate:OnEventStart();
Lua使用C#获得二维数组的值
print("*********Lua调用C#二维数组相关知识点*********");
--Lua使用C#的数组,并直接通过索引查找数组元素只适用于一维数组。
--想要获得多维数组的元素需要使用Array基类中的一个获取元素的方法GetValue。
--同理如果我们想要设置多维数组的值也可以通过方法SetValue来实现。
--注意这里的GetSet都为成员方法。
local Call2Array = CS.Call2Array();
--获得C#2维数组的行长度
print(Call2Array.My2Array:GetLength(0));
--获得C#2维数组的列长度
print(Call2Array.My2Array:GetLength(1));
--获得C#2维数组的元素,我们需要通过GetValue方法来实现。
--获得索引为(0,0)的元素
print(Call2Array.My2Array:GetValue(0,0));
--获得索引为(1,2)的元素
print(Call2Array.My2Array:GetValue(1,2));
--遍历C#二维数组
for i=0,Call2Array.My2Array:GetLength(0) - 1 do
for j=0, Call2Array.My2Array:GetLength(1) - 1 do
print(Call2Array.My2Array:GetValue(i,j));
end
end
Lua调用C#nil和null的比较
print("*********Lua调用C#nil和null相关知识点*********");
--首先我们需要明白:C#中的null和lua中的nil是不能判等的。
--我们用一个开发中比较常见的问题来说明这个问题。
--问题:判断一个游戏物体是否存在rigidbody,如果不存在需要添加一个tigidbody组件。
local GameObject = CS.UnityEngine.GameObject;
local Rigidbody = CS.UnityEngine.Rigidbody;
local go = GameObject("添加Rigidbody");
local rigi = go:GetComponent(typeof(Rigidbody));
--解决方式一:使用Equals
if rigi:Equals(nil) then
go:AddComponent(typeof(Rigidbody));
end
--再次判断go物体上是否有Rigidbody组件
local rigi = go:GetComponent(typeof(Rigidbody));
--解决方式二:在Main中或者调用Main的调用函数中书写全局判空函数并使用。
--[[
function IsNull(param)
if param == nil or param:Equals(nil) then
return true;
end
return false;
end
]]
if IsNull(rigi) then
print("123");
go:AddComponent(typeof(Rigidbody));
end
--再次判断go物体上是否有Rigidbody组件
local rigi = go:GetComponent(typeof(Rigidbody));
--解决方式三:在C#中为Object书写判空拓展方法并使用。
--[[
[LuaCallCSharp]
public static class NilAndNull{
public static bool IsNull(this Object obj)
{
return obj == null;
}
}
]]
if rigi:IsNull() then
print("123");
go:AddComponent(typeof(Rigidbody));
end
CSharpCallLua和LuaCallCsharp特性
使用时机:
CSharpCallLua:当我们使用C#的接口和委托接收lua代码时(CSharp为主场),我们需要为C#类提供这个特性。另外一种情况是当我们需要使用Lua调用C#的系统类型的时候,同样需要使用到该特性。
LuaCallCsharp:当我们使用Lua调用C#时(Lua为主场),我们建议所有被lua调用的类都加上这个特性。
这两个特性保证了自定义C#类和lua代码之间的调用,但我们不能通过这两个特性实现系统类型和lua代码之间的调用。
Lua使用C#系统类型
上面对于两个特性的比较已经说明了其使用时机,但是我们注意到,当我们想用lua调用Csharp中系统类型时。我们没有办法为系统类型添加特性,这时我们就需要用到xlua的特性列表。
print("*********Lua调用C#系统类型相关知识点*********");
--这里我们用unity中的Slider为例
local GameObject = CS.UnityEngine.GameObject;
local Slider = CS.UnityEngine.UI.Slider;
local go = GameObject.Find("Slider");
print(go);
local sliderScript = go:GetComponent(typeof(Slider));
print(sliderScript);
--[[
这里直接添加监听事件,会直接报错提示需要为UnityAction添加[CSharpCallLua]的特性。
但我们知道我们是不可以改变系统类型的,所以我们需要用到xlua提供的特性列表:
[CSharpCallLua]
public static List<Type> CSharpCallLuaList = new List<Type>()
{
typeof(UnityAction<float>),
};
[LuaCallCSharp]
public static List<Type> LuaCallCSharpList = new List<Type>()
{
typeof(GameObject),
typeof(Rigidbody),
};
这两个分别为[CSharpCallLua]特性列表和[LuaCallCSharp]特性列表。
我们只需要在里面写我们想要添加特性的类型就可以了,之后重新生成代码,Xlua就会帮我们构建可以使用的中间代码。
特性列表还有一大用途就是集中添加我们需要申明特性的类,这会使我们的代码更加专业和简洁。
完成特性列表的书写后我们就可以通过lua来调用C#或者unity中的系统类型了。
需要注意:
特性列表和特性列表所在的类一定都为静态的。
]]
sliderScript.onValueChanged:AddListener(function(value)
print(value);
end);
Lua使用C#协程
print("*********Lua调用C#协程相关知识点*********");
local GameObject = CS.UnityEngine.GameObject;
local WaitForSeconds = CS.UnityEngine.WaitForSeconds;
--Lua调用C#的协程需要注意几点:
--[[
1. 建议将所有用到的和C#协程有关的类都预先保存
2. Lua不能直接使用C#协程中的yield return
3. 虽然我们使用lua调用C#的StartCoroutine来开启协程,但是协程函数的书写使用Lua语法书写
4. lua协程不能直接传入StartCoroutine中,我们需要接用xlua为我们提供的util工具表来实现
5. 由于调用的是C#的协程启动和停止相关的函数,所以除过协程本身的书写,其他也还是遵循C#的规则
]]
--加载xlua提供给我们的util工具表
util = require("xlua.util");
--首先我们先来创建一个游戏物体
local go = GameObject("Coroutine");
local mono = go:AddComponent(typeof(CS.CsharpCallLua.CallCoroutine));
--书写lua协程
func = function()
local param = 1;
while true do
--使用lua的yield来暂停协程
coroutine.yield(WaitForSeconds(1));
print(param);
param = param + 1;
--如果param大于10,我们就停止协程
if param > 10 then
mono:StopCoroutine(cor);
end
end
end
--使用C#的StartCoroutine开启lua协程,这里使用util工具表辅助实现
cor = mono:StartCoroutine(util.cs_generator(func));
Lua使用C#泛型函数
print("*********Lua调用C#泛型相关知识点*********");
local callT = CS.CallT();
local chlid = CS.CallT.InnerChild();
local father = CS.CallT.InnerFather();
--lua仅支持有约束有参数且约束为类的泛型函数
callT:TestFunc1(child,father);
callT:TestFunc1(father,child);
--lua不支持没有参数的泛型函数
--callT:TestFunc2();
--lua不支持没有约束的泛型函数
--callT:TestFunc3(child);
--lua不支持非class的约束
--callT:TestFunc4();
--补充知识:xlua为我们提供了对应的转换方法,但是慎用
--[[
此方法的有一定的限制:
1. 如果我们的游戏项目是Mono打包则这种方式是完全支持的;但如果我们的项目是IL2CPP打包,则只有引用类型可以使用。
]]
--[[
1. 使用get_generic_method方法得到通用函数
xlua.get_generic_method(类, 函数名字符串);
2. 使用通用函数设置泛型类型
3. 调用设置了泛型类型的通用函数。
]]
local testFunc3 = xlua.get_generic_method(CS.CallT, "TestFunc3");
local testFunc3_R = testFunc3(CS.CallT.InnerFather);
--[[
调用:
1. 成员方法:第一个参数需要穿阿如调用函数的对象。
2. 静态方法:不需要传调用对象。
]]
testFunc3_R(callT, father);