SLua 实现原理
0. SLua 实现分成两个部分:c层和c#层
c层主要是lua或者luajit,加一个c层的接口,以及一些可以添加的第三方库
c#层:主要解决:
如何调用lua代码
lua如何调用c#代码
c#对象如何传递给lua
lua对象如何传递给c#
这些问题。
1. 调用lua代码
LuaDll 导入了lua相关的c接口,用于c#调用
2. lua调用c#方法
通过lua_pushcfunction 将c#函数转化为c函数,传递给lua代码,接着可以设置lua中table的某个成员对应于这个c函数, 这种方式,c#中的函数如果被gc了,会有问题。
lua_pushcfunction
lua_setglobal
上面可以简单的设定全局函数
3. c#对象传递给给lua代码
跨语言传递对象,最简单的方式,将对象序列化为字符串传递过去;
对于简单值对象,可以序列化方式传递;
复杂类对象,可以创建一个LuaTable,用于对应于c#中的类对象,将c#类的函数注册到table中,将对属性的访问和设置,注册get set 函数即可。
在c#层可以保存一个id到object的映射表,当需要从Lua调用c#对象的方法,只需要告知对象的id,接着在C#层根据id获得到对象即可
4. Lua对象传递给c#
Lua对象包括简单的值对象,复杂的table对象。
值对象直接从堆栈上返回
table对象在c# LuaTable来表示,在lua中可以将lua的table存储起来,通过id进行索引,而将id传给 c#层,当c#层需要访问table数据,只需要根据id调用对应接口即可。
5. 静态绑定代码生成
当lua中需要调用c#中某个类的接口的时候,首先lua需要获得这个c#对象,接着调用c#对象函数接口;
Lua中获得某个c#对象,可以是通过c#的静态方法,或者成员方法。
简单的从静态方法开始考虑:
首先Lua中需要有该类的一个Table,这个table中的有静态方法的c函数可以供lua调用。
Lua的全局global table可以注册名字,这样在lua全局代码中就可以调用这个名字;
当调用某个方法返回c#对象,将c#对象放置到c#的列表中,而将对应的id返回给lua。
6. 对象生命周期管理
当Lua中引用c#对象,如何当lua引用结束的时候,通知c#中的管理代码,来去除对象?
当c#引用lua对象,如何管理Lua对象的生命周期呢?
Lua table可以添加一个metatable用于重载lua系统默认的一些接口的操作,重载__gc 接口,可以再lua 回收资源时候,调用c#代码进行清理工作,这样当lua不需要c#对象的时候,可以将对象回收。
c#引用luatable对象,如何释放掉?c#对象可以实现 IDisposable 接口,当C#对象被GC的时候,释放对lua对象的引用。
通过 luaL_ref luaL_unref, 即将 table中对应id的项情况。
7. 异常处理
当lua调用c#代码发生异常,在c#代码中添加了异常捕获,当出现异常将向堆栈压入false以及异常信息,而如果没有异常,将压入true,以及正常的返回值;
而在压入c#函数到lua中时候,压入一个闭包,而在lua的这个闭包调用正常的csharp函数,检查返回是否有异常,存在异常,则抛出一个lua_error,或者用lua的 assert抛出一个异常
当c#调用lua代码发生异常,c#可以使用lua_pcall 来执行lua代码,可以传入相应的异常处理函数,来打印出lua的异常以及堆栈信息。