lua与C交互:基于栈操作,lua调用C函数时,需要写个封装函数,从栈上取出调用参数,调用C函数后把结果放到栈上;C要调用lua函数,也把参数放到栈上,用luaAPI完成调用后,从栈上取出结果。
Xlua lua调用C#
1. 没有生成静态代码,反射调用
a.把C#对象映射到lua的userdata,userdata只保留一个信息,就是这个对象在C#侧的objects_pool的索引
b.根据obj获取其ClassType,根据type与调用函数(位置栈里边index2),通过反射获取实际执行的MethodInfo
c.根据MethodInfo构造一个满足LuaCSFunction的delegate并压栈
d.delegate构造,根据MethodInfo,取得args信息,根据args从栈中取出赋值,反射调用函数后把结果压栈;GetAsType是把栈上Lua对象转换成指定类型的C#对象,PushCsObject是把一个C#对象按映射规则压到Lua栈上
e.将统一的反射调用方法objectIndex设置为所有C#对象的metatable的__index
lua_call_Csharp示例:
[MonoPInvokeCallback(typeof(LuaCSFunction))]
public static int objectIndex(RealStatePtr L)
{
object obj = objects_pool[GetCSObjectId(L, 1)];
Type objType = obj.GetType();
string index = LuaAPI.lua_tostring(L, 2);
MethodInfo method = objType.GetMethod(index);
PushCSFunction(L, (IL) =>
{
ParameterInfo[] parameters = method.GetParameters();
object[] args = new object[parameters.Length];
for(int i = 0; i < parameters.Length; i++)
{
args[i] = GetAsType(IL, i + 2, parameters[i].ParameterType);
}
object ret = method.Invoke(obj, args);
PushCSObject(IL, ret);
return 1;
});
return 1;
}
Csharp_call_lua示例:
public object[] Call(params object[] args)
{
int old_top = LuaAPI.lua_gettop(L);
LuaAPI.lua_getref(L, func_ref);
for(int i = 0; i < args.Length; i++)
{
Type arg_type = args[i].GetType();
if (arg_type == typeof(double))
{
LuaAPI.lua_pushnumber(L, (double)args[i]);
}
// ... other c# type
}
LuaAPI.lua_call(L, args.Length, -1);
object[] ret = new object[LuaAPI.lua_gettop(L) - old_top];
for(int i = 0; i < ret.Length; i++)
{
int idx = old_top + i + 1;
if(LuaAPI.lua_isnumber(L, idx))
{
ret[i] = LuaAPI.lua_tonumber(L, idx);
}
// ... other lua type
}
return ret;
}
2. 非反射,静态生成代码
反射带来的问题:a.拆装箱开销 b.stripping引用的反射失效 c.泛型方法,触发JIT,引起IOS异常 d.失去静态检查好处
非反射做法:用反射的方式,用工具生成要用在lua侧调用的类的,类似反射调用代码(见lua_call_Csharp示例),只是去除了里边的反射内容,因为针对每个类是确定的,不需要用反射
静态代码的问题:
a.生成时,有宏定义的方法,如Editor会有问题
b.生成的代码,增大编译后的代码大小,尤其il2cpp,相应地增加包体大小
参考:https://gameinstitute.qq.com/community/detail/105650
原文:https://www.cnblogs.com/hiker-online/p/13603400.html