Lua的function传递到C#后,对应的是C#的委托,同样以TestXLua类为例来分析具体过程
// 注意,这里添加的LuaCallCSharp特性只是为了使xLua为其生成代码,不添加并不影响功能 [LuaCallCSharp] public class TestXLua { [CSharpCallLua] public delegate int Func(string s, bool b, float f); public static Func func; }点击Generate Code后,生成的部分TestXLuaWrap代码如下所示。为func变量生成了对应的set和get包裹方法
// TestXLuaWrap.cs [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int _g_get_func(RealStatePtr L) { try { ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L); translator.Push(L, TestXLua.func); } catch(System.Exception gen_e) { return LuaAPI.luaL_error(L, "c# exception:" + gen_e); } return 1; } [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int _s_set_func(RealStatePtr L) { try { ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L); TestXLua.func = translator.GetDelegate<TestXLua.Func>(L, 1); } catch(System.Exception gen_e) { return LuaAPI.luaL_error(L, "c# exception:" + gen_e); } return 0; }为func静态变量赋值一个Lua function
-- Lua测试代码 CS.TestXLua.func = function(s, b, i) end上述代码在赋值时,会最终调用_s_set_func包裹方法(具体原理可以查看这里),Lua在调用_s_set_func前,会将参数function压入到栈中,因此_s_set_func内部需要通过translator.GetDelegate拿到这个function,并将其赋值给func静态变量
// ObjectTranslator.cs public T GetDelegate<T>(RealStatePtr L, int index) where T :class { if (LuaAPI.lua_isfunction(L, index)) { return CreateDelegateBridge(L, typeof(T), index) as T; } else if (LuaAPI.lua_type(L, index) == LuaTypes.LUA_TUSERDATA) { return (T)SafeGetCSObj(L, index); } else { return null; } }对于Lua function类型会通过CreateDelegateBridge创建一个对应的委托并返回。CreateDelegateBridge内部会创建一个DelegateBridge对象来对应Lua function,原理和LuaTable类似,也是通过一个索引保持联系,利用这个索引可以获取到Lua function
// ObjectTranslator.cs Dictionary<int, WeakReference> delegate_bridges = new Dictionary<int, WeakReference>(); // 弱引用创建的DelegateBridge public object CreateDelegateBridge(RealStatePtr L, Type delegateType, int idx) { LuaAPI.lua_pushvalue(L, idx); LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX); // 对缓存的处理 if (!LuaAPI.lua_isnil(L, -1)) { int referenced = LuaAPI.xlua_tointeger(L, -1); LuaAPI.lua_pop(L, 1); if (delegate_bridges[referenced].IsAlive) { if (delegateType == null) { return delegate_bridges[referenced].Target; } DelegateBridgeBase exist_bridge = delegate_bridges[referenced].Target as DelegateBridgeBase; Delegate exist_delegate; if (exist_bridge.TryGetDelegate(delegateType, out exist_delegate)) { return exist_delegate; } else { exist_delegate = getDelegate(exist_bridge, delegateType); exist_bridge.AddDelegate(delegateType, exist_delegate); return exist_delegate; } } } else { LuaAPI.lua_pop(L, 1); } LuaAPI.lua_pushvalue(L, idx); int reference = LuaAPI.luaL_ref(L); // 将idx处的元素添加到Lua注册表中 LuaAPI.lua_pushvalue(L, idx); LuaAPI.lua_pushnumber(L, reference); LuaAPI.lua_rawset(L, LuaIndexes.LUA_REGISTRYINDEX); // 注册表[idx值] = reference DelegateBridgeBase bridge; try { #if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0 if (!DelegateBridge.Gen_Flag) { bridge = Activator.CreateInstance(delegate_birdge_type, new object[] { reference, luaEnv }) as DelegateBridgeBase; // 使用反射创建DelegateBridge对象 } else #endif { bridge = new DelegateBridge(reference, luaEnv); } } catch(Exception e) { LuaAPI.lua_pushvalue(L, idx); LuaAPI.lua_pushnil(L); LuaAPI.lua_rawset(L, LuaIndexes.LUA_REGISTRYINDEX); LuaAPI.lua_pushnil(L); LuaAPI.xlua_rawseti(L, LuaIndexes.LUA_REGISTRYINDEX, reference); throw e; } if (delegateType == null) { delegate_bridges[reference] = new WeakReference(bridge); return bridge; } try { var ret = getDelegate(bridge, delegateType); // 通过bridge获取到指定类型的委托 bridge.AddDelegate(delegateType, ret); delegate_bridges[reference] = new WeakReference(bridge); return ret; } catch(Exception e) { bridge.Dispose(); throw e; } }