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的异常以及堆栈信息。

本文来自:https://my.oschina.net/u/186074/blog/724039