概括:
通过栈来实现。lua调用c#就是将lua层的参数和c#导出函数入栈,然后执行函数。c#调用lua就是将c#层的参数和lua函数入栈,然后执行函数
虚拟栈
Lua在C函数和脚本函数之间创建了一种虚拟栈的结构,栈的元素代表一个Lua的值(table, string, nil等等8种基本类型)。Lua提供了一系列C API用于操作栈,比如将元素入栈,出栈,删除等等。在调用这些API之前,通常都需要将必须的值压入栈,在API调用结束后,再把结果从栈中取出。记住越往下越小,1表示栈底,-1表示栈顶
luaState的概念
luaState 中放的是 lua 虚拟机中的环境表、注册表、运行堆栈、虚拟机的上下文等数据。可以理解为我们写代码常用的各种manager类。在xLua中luaState被封装成了LuaEnv类,在toLua中叫作LuaState。
var L = LuaDLL.luaL_newstate();
lua_pcall
lua_pcall(lua_State *L,int nargs,int nresults,int errfunc)
nargs 参数个数
nresults 返回值个数
errFunc 错误处理函数,0表示无,表示错误处理函数在栈中的索引
C#调用Lua:传入C#参数,调用Lua方法
lua代码
function addandsub(x,y)
return x+y,x-y
end
C#把C#端参数入栈,lua_pcall调用,lua中返回值,依次放入栈顶
private void CallLuaFunction( IntPtr L )
{
var path = Application.dataPath + "/LuaTest/Examples/03_Function/03.lua";
Debug.Log(path);
LuaDLL.luaL_loadfile( L, path );//执行lua文件,也可以luaL_dostring(L, string);执行lua字符串代码
LuaDLL.lua_pcall( L, 0, 0, 0 );
LuaDLL.lua_getglobal( L, "addandsub");//获取全局变量的addandsub的值,并将其放入栈顶
LuaDLL.lua_pushnumber( L, 10 );//栈顶压入10
LuaDLL.lua_pushnumber( L, 20 );//栈顶压入20
if( LuaDLL.lua_pcall( L, 2, 2, 0 ) != 0 ) //执行函数,输入2个值,返回2个值,不为0,有错误
{
Debug.LogError( LuaDLL.lua_tostring( L, -1 ) );
}
Debug.Log( LuaDLL.lua_tonumber( L, -1 ) );//栈-2,为-10
Debug.Log( LuaDLL.lua_tonumber( L, -2 ) );//栈-1,为30,,因为返回值是先入栈
}
1.先将方法入栈
2.再将方法需要的参数按顺序入栈
3.调用 lua_pcall
4.此时lua会把返回值入栈
Lua调用C#
private void LuaHelloWorld( IntPtr L )
{
LuaDLL.lua_pushcclosure( L, HelloWorld, 0 );
LuaDLL.lua_pcall( L, 0, 0, 0 );
}
[MonoPInvokeCallbackAttribute( typeof( LuaCSFunction ) )]
private static int HelloWorld( IntPtr L)
{
Debug.Log( "helloworld:" );
return 0;
}
- 定义委托
- 定义委托对应函数
- 将方法转为指针
- 将函数入栈lua_pushcclosure
其他相关
// 新建一个Lua解释器,每一个Lua实例都相互独立, 一个global全局域
Lua lua = new Lua();
//---------------------------------------------------lua调用c#函数
TestClass obj = new TestClass();
// 注册CLR对象方法到Lua,供Lua调用 typeof(TestClass).GetMethod("TestPrint")
lua.RegisterFunction("TestPrint", obj, obj.GetType().GetMethod("TestPrint"));
// 注册CLR静态方法到Lua,供Lua调用
lua.RegisterFunction("TestStaticPrint", null, typeof(TestClass).GetMethod("TestStaticPrint"));
lua.DoString("TestPrint(10)");
lua.DoString("TestStaticPrint()");
CLR(Common Language Runtime)是一个可由多种编程语言使用的“运行时”。(例如:c#,c++/cli,vb,f#,ironpython,ironruby,il…)
CLR的核心功能内存管理、程序集加载、安全性、异常处理、线程同步、泛型、尾调用指令和基本的公共语言基础结构 (CLI) 类型系统等。
本地代码编译器生成的是面向特定cpu架构的代码。相反每个面向clr的编译器生成的都是il代码。源代码文件----》编译器----》托管模块
测试用代码
https://github.com/luoyikun/UnityForTest Lua2CSharpTest场景