首先,感谢蒙哥让我能用上这么方便的一个lua框架-tolua
我想大家在使用tolua的时候,在做c#包装类(即wrap文件的时候),都会不由的感叹,原来lua和c#交互竟然那么简单,那么请问有谁真正的了解过这些wrap文件的原理,这些文件又是如何在虚拟机之中运行的呢,intptr这个类的作用又是什么,里面的topointer方法有没有想过之间隐藏的含义,那么我接下来会慢慢bb的。
阅读一下部分,请了解lua寄存器虚拟机的基础知识,不明白可以看我上一篇文章最前面部分关于lua虚拟机介绍,有了这个概念你才可以继续阅读
1.tolua如何将c#对象导入到lua里
tolua为每一个传入lua的对象建立一个userdata,userdata的值,是c#对象的地址。userdata的metatable,是一个tolua建立的,记录了userdata对应c#类型信息的表格,包括导出的成员变量、成员函数等信息。
对于成员变量的读取赋值,tolua是在metatable里新建了.get和.set两个表。两个表里分别存储了以变量名为键,以读取设置c #函数为值的表项。在metatable的__index和__newindex里,以变量名为键,从.get和.set表里取得读取设置函数并调用。
传入c#对象的tolua函数是tolua_pushusertype。一般情况下,第一次使用这个函数将一个c#对象push到lua堆 栈上时,才会新建userdata。tolua会以c#对象地址为键,userdata为值,将键值对存储在tolua_ubox表里。下次推入同 样的c#对象时,从这个表里取出userdata推入堆栈即可。
我导入一个之前wrap类型的函数做介绍
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
static int Create(IntPtr L)
{
try
{
Tolua.CheckArgsCount(L,3);
Cos.Battlefield.BattlefieldManager obj = ( Cos.Battlefield.BattlefieldManager ) ToLua.CheckObject<Cos.Battlefiled.BattlefieldManager>(L,1);
LuaTable arg0 = ToLua.CheckLuaTable(L,2);
LuaTable arg1 = ToLua.CheckLuaTable(L,3);
obj.Create(arg0,arg1);
return 0;
}
catch(Exception e)
{
return LuaDll.toluaL_exception(L,e);
}
}
请结合文字加上这个wrap类方法代码,想一下文字里面的逻辑,然后再继续看,自己的理解有时候即使错误也比直接给答案的意义要大得多
现在,你大概知道了这个IntPtr是什么玩意了,我查了下百度(~ !~),解释如下
用于表示指针或句柄的平台特定类型。
**命名空间:**System
**程序集:**mscorlib(在 mscorlib.dll 中)
链接:https://docs.microsoft.com/zh-cn/previous-versions/dotnet/netframework-1.1/5he14kz8(v=vs.80)
那么我们lua调用一个c#对象的原理就很简单过,首先创建或者获取
传入c#对象的tolua函数是tolua_pushusertype。一般情况下,第一次使用这个函数将一个c#对象push到lua堆 栈上时,才会新建userdata。tolua会以c#对象地址为键,userdata为值,将键值对存储在tolua_ubox表里。下次推入同 样的c#对象时,从这个表里取出userdata推入堆栈即可。
然后调用,调用首先要把userdata压入堆栈,所以上面c#代码里面参数IntPtr就是一个内存地址,然后通过Tolua.CheckArgsCount(L,3);拿到了这块内存地址的BattlefieldManager 对象和lua传递过来的两个参数(因为L内存地址顺序是连续的)
LuaTable arg0 = ToLua.CheckLuaTable(L,2);
LuaTable arg1 = ToLua.CheckLuaTable(L,3);
最后使用这个对象,传入参数,调用方法,执行完毕,这样你是否对于tolua的理解更深一步了呢,如果有小伙伴希望了解lua的知识,可以留言,我会的会在评论中回复,谢谢观看 |