概括:

通过栈来实现。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;
}
  1. 定义委托
  2. 定义委托对应函数
  3. 将方法转为指针
  4. 将函数入栈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场景