zoukankan      html  css  js  c++  java
  • Lua调用c#发生了什么?

    目录:Xlua源码学习

    本篇以CS.XLua.LuaDLL.Lua:xlua_is_eq_str(L,index,str)的调用为例子。

    文章比较长,先说结论:

    1.CSLuaEnvinit_xlua代码块里生成的全局表,核心init_xlua里的metatable:__index方法。

    2. XLua:以XLua为类名的类不存在,当做命名空间处理。CS.XLua = { ['.fqn'] = fqn }

    3. LuaDLL:同上,CS.XLua.LuaDLL = { ['.fqn'] = fqn }

    4. LuaLua类存在,导出类。

       调用StaticLuaCallbacks.ImportType导出类。

    ObjectTranslator.TryDelayWrapLoader:调用wrap的__Register方法加载类。

    __Register:生成元表obj_meta,该元表封装了类的所有成员方法、get、set调用接口__index,__newindex。

    生成cls_table,该表包含了所有类的静态方法。

    生成cls_meta,cls_table的元表,封装了静态的属性设置、获取接口__index,__newindex。

    设置CS.XLua.LuaDLL.Lua = cls_table。

    类导出结束。

    5.调用静态方法

    1. 静态方法获取:cls_table.staticFunc,直接取。

    2. 静态get方法:通过cls_meta的__index(xlua.c的cls_indexer)获取,非父类方法存在getters。

    3. 静态父类方法:通过cls_meta的__index(xlua.c的cls_indexer)获取,实际通过父类的cls_index获取的,即register["LuaClassIndexs"][base_ud] = base_meta.__index。涉及父类操作下同。

    4. 静态set:通过cls_meta的__newindex(xlua.c的cls_newindexer)获取,非父类方法存在setters。

    6.对象实例获取:

    两种方式:

    1. new一个对象,例如在lua执行UIHierarchy(),会触发UIHierarchy的cls_meta的__call方法,而__call方法绑定了下面的UIHierarchyWrap .__CreateInstance(),最终是new了一个对象,然后把实例对象的ud压栈返回,你就可以通过这个ud的元表obj_meta调用到成员方法。

    static int __CreateInstance(RealStatePtr L)
    {        
        try {
           ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
           if(LuaAPI.lua_gettop(L) == 1)
           {    
              UIHierarchy gen_ret = new UIHierarchy();
              translator.Push(L, gen_ret);
              return 1;
           }  
        }
    }

    2. 从其他方法返回值获取,例如gameobject.transform会把transform的ud压栈并返回并lua,lua通过这个ud进行成员方法的访问。

    static int _g_get_transform(RealStatePtr L)
    {
        try {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
    
            UnityEngine.GameObject gen_to_be_invoked = (UnityEngine.GameObject)translator.FastGetCSObj(L, 1);
            translator.Push(L, gen_to_be_invoked.transform);
        } catch(System.Exception gen_e) {
            return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
        }
        return 1;
    }

    6.调用成员方法

    1. 通过压栈的ud的元表obj_meta访问__index方法(xlua.c的obj_indexer),取到方法,非父类方法存在methods。

    2. 成员get:同上。

    3. 成员set: 通过压栈的ud的元表访问__newindex方法(xlua.c的obj_newindexer),取到方法。

    4. lua方法调用时会依次把参数压栈,成员方法(:)调用会先把自身的ud压栈,再根据ud到objects缓存取到对应的obj实例进行调用。

    static int _s_set_widgets(RealStatePtr L)
      {
    try {
              ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
    
              UIHierarchy gen_to_be_invoked = (UIHierarchy)translator.FastGetCSObj(L, 1);//第一个参数,自身ud地址。
              gen_to_be_invoked.widgets = (System.Collections.Generic.List<UIHierarchy.ItemInfo>)translator.GetObject(L, 2, typeof(System.Collections.Generic.List<UIHierarchy.ItemInfo>));
          
          } catch(System.Exception gen_e) {
              return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
          }
          return 0;
      }

    一、CS全局表。

    LuaEnv的构造方法里会执行init_xlua文本,在这个可执行的文本里生成里CS的全局表,并对CS赋了值

    CS = Register["CSHARP_NAMESPACE"]

    DoString(init_xlua, "Init");
    
    LuaAPI.xlua_pushasciistring(rawL, CSHARP_NAMESPACE);
    if (0 != LuaAPI.xlua_getglobal(rawL, "CS"))
    {
        throw new Exception("get CS fail!");
    }
    LuaAPI.lua_rawset(rawL, LuaIndexes.LUA_REGISTRYINDEX);

    init_xlua核心的代码段如下:

    function metatable:__index(key) 
        local fqn = rawget(self,'.fqn')
        fqn = ((fqn and fqn .. '.') or '') .. key
    
        local obj = import_type(fqn)
    
        if obj == nil then
            -- It might be an assembly, so we load it too.
            obj = { ['.fqn'] = fqn }
            setmetatable(obj, metatable)
        elseif obj == true then
            return rawget(self, key)
        end
    
        -- Cache this lookup
        rawset(self, key, obj)
        return obj
    end
    
    function metatable:__newindex()
        error('No such type: ' .. rawget(self,'.fqn'), 2)
    end

    __index的官方说明如下:

    __index: 索引 table[key]。 当 table 不是表或是表 table 中不存在 key 这个键时,这个事件被触发。 此时,会读出 table 相应的元方法。

    这个事件的元方法其实可以是一个函数也可以是一张表。 如果它是一个函数,则以 table 和 key 作为参数调用它。 如果它是一张表,最终的结果就是以 key 取索引这张表的结果。 (这个索引过程是走常规的流程,而不是直接索引, 所以这次索引有可能引发另一次元方法。)

    这段lua的意思是,如果table[className] 不存在,则执行这个__index。如果className对应的类型存在,加载这个类型到内存(wrap的__Register),否则创建一张空表,当成命名空间处理。

    这边的obj是cls_table,这个表里存着这个类对应wrap的所有静态方法,通过这个类的wrap文件的__CreateInstance方法可以获取这个类的ud,而这个ud的元表里封装了可以获取类的成员方法、属性的_index方法。这边所指的方法都是在wrap里面的。具体后面再说。

    __newindex:实际是禁止了对这个表的元表设置操作。

    二、命名空间:XLuaLuaDLL

    如上的index代码,local obj = import_type(fqn)。这个obj是nil,那么这边是创建了两个空表。即

    CS.XLua = {['.fqn'] = fqn}

    CS.XLua.LuaDLL = {['.fqn'] = fqn}

    三、import_type,加载wrap文件进内存。

    1.这边的import_type实际是StaticLuaCallbacks.ImportType方法。

    核心代码如下,type == null,当做命名空间处理。否则通过translator.GetTypeId加载类。

    ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            string className = LuaAPI.lua_tostring(L, 1);
            Type type = translator.FindType(className);
            if (type != null)
            {
                if (translator.GetTypeId(L, type) >= 0)
                {
                    LuaAPI.lua_pushboolean(L, true);
                }
                else
                {
                    return LuaAPI.luaL_error(L, "can not load type " + type);
                }
            }
            else
            {
                LuaAPI.lua_pushnil(L);
            }

    2.translator.getTypeId:获取type元表在注册表中引用Id,如果不存在,则创建元表registry[type.FullName]={},并在registry表中创建新的引用指向该元表并返回type_id。维护了TypeTypeId间的映射表typeMaptypeIdMap

    internal int getTypeId(RealStatePtr L, Type type, out bool is_first, LOGLEVEL log_level = LOGLEVEL.WARN)
    {
        int type_id;
        is_first = false;
        if (!typeIdMap.TryGetValue(type, out type_id)) // no reference
        {
            is_first = true;
            Type alias_type = null;
            aliasCfg.TryGetValue(type, out alias_type);
            LuaAPI.luaL_getmetatable(L, alias_type == null ? type.FullName : alias_type.FullName);
    
            if (LuaAPI.lua_isnil(L, -1)) //no meta yet, try to use reflection meta
            {
                LuaAPI.lua_pop(L, 1);
    
                if (TryDelayWrapLoader(L, alias_type == null ? type : alias_type))
                {
                    LuaAPI.luaL_getmetatable(L, alias_type == null ? type.FullName : alias_type.FullName);
                }
            }
    
            //循环依赖,自身依赖自己的class,比如有个自身类型的静态readonly对象。
            if (typeIdMap.TryGetValue(type, out type_id))
            {
                LuaAPI.lua_pop(L, 1);
            }
            else
            {
                LuaAPI.lua_pushvalue(L, -1);
                type_id = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);//register["type_id"] = meta
                LuaAPI.lua_pushnumber(L, type_id);
                LuaAPI.xlua_rawseti(L, -2, 1);//meta["1"] = typeId
                LuaAPI.lua_pop(L, 1);
    
                if (type.IsValueType())
                {
                    typeMap.Add(type_id, type);
                }
    
                typeIdMap.Add(type, type_id);
            }
        }
        return type_id;
    }

    3. TryDelayWrapLoader

    delayWrap在XLua_Gen_Initer_Register__.Init赋值,Init方法在ObjectTranslator的s_gen_reg_dumb_obj参数生成里调用(即构造函数前就初始化好了)。他实际是Type到TypeWrap.__Register的映射。

    下面的loader(L);实际调用的是对应类的wrap文件的__Register方法。

    public bool TryDelayWrapLoader(RealStatePtr L, Type type)
            {
                if (loaded_types.ContainsKey(type)) return true;
                loaded_types.Add(type, true);//避免重复加载
    
                LuaAPI.luaL_newmetatable(L, type.FullName); //先建一个metatable,因为加载过程可能会需要用到
                LuaAPI.lua_pop(L, 1);
    
                Action<RealStatePtr> loader;
                int top = LuaAPI.lua_gettop(L);
                if (delayWrap.TryGetValue(type, out loader))
                {
                    delayWrap.Remove(type);
                    loader(L);
                }   
                return true;
            }

    四、类的核心加载方法XXXWrap.__Register

    这边不贴代码了,核心方法都在Utils类里。

    public static void __Register(RealStatePtr L)
    {
        ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
        System.Type type = typeof(UIHierarchy);
    
        Utils.BeginObjectRegister(type, L, translator, 0, 2, 3, 3);
        Utils.RegisterFunc(L, Utils.METHOD_IDX, "SetWidgets", _m_SetWidgets);
        Utils.RegisterFunc(L, Utils.GETTER_IDX, "widgets", _g_get_widgets);       
        Utils.RegisterFunc(L, Utils.SETTER_IDX, "widgets", _s_set_widgets);       
        Utils.EndObjectRegister(type, L, translator, null, null,
        null, null, null);
    
        Utils.BeginClassRegister(type, L, __CreateInstance, 1, 0, 0);
        Utils.RegisterFunc(L, Utils.CLS_IDX, "IsNull", _m_IsNull_xlua_st_);
        Utils.EndClassRegister(type, L, translator);
    }

    1.BeginObjectRegister:生成类的成员元表、成员方法、GetSet的存放表。

    obj_meta[ud]=1

    obj_meta["__gc"]=StaticLuaCallbacks.LuaGC

    obj_meta["__tostring"]=StaticLuaCallbacks.ToString

    方法执行结束:obj_meta, methon, get, set(-4, -3, -2, -1)

    2.Utils.RegisterFunc:注册方法,这个比较简单,就是做一次赋值。

    method_table[name] = func,这边包括method、set、get等方法设置。

    这边其实把lua调用的方法都封装成LuaCSFunction委托,再转成指针赋值给c,c在把这个函数指针封装成闭包供lua调用。

    public static void RegisterFunc(RealStatePtr L, int idx, string name, LuaCSFunction func)
    {
       idx = abs_idx(LuaAPI.lua_gettop(L), idx);
       LuaAPI.xlua_pushasciistring(L, name);
       LuaAPI.lua_pushstdcallcfunction(L, func);
       LuaAPI.lua_rawset(L, idx);
    }
    
    public static void lua_pushstdcallcfunction(IntPtr L, lua_CSFunction function, int n = 0)//[-0, +1, m]
    {
        IntPtr fn = Marshal.GetFunctionPointerForDelegate(function);//转指针
        xlua_push_csharp_function(L, fn, n);
    }

    xlua.c接口

    static int csharp_function_wrap(lua_State *L) {
       lua_CFunction fn = (lua_CFunction)lua_tocfunction(L, lua_upvalueindex(1));
        int ret = fn(L);    
        return ret;
    }
    
    LUA_API void xlua_push_csharp_function(lua_State* L, lua_CFunction fn, int n)
    { 
        lua_pushcfunction(L, fn);
        lua_pushboolean(L, 0);
        lua_pushcclosure(L, csharp_function_wrap, 2 + (n > 0 ? n : 0));
    }

    3.EndObjectRegister:设置成员元表的__index__newindex方法。

    方法开始堆栈:obj_meta,methon,get,set

    栈中内容:obj_meta,method,get,set,--index,method,get,csIndexer(array),baseType(父类),register[luaindex],arrayIndexer(nil)

    LuaAPI.gen_obj_indexer(L); //设置__index方法

    栈中内容:obj_meta,method,get,set,--index, closure(xlua.c 的obj_indexer)

    这个闭包如下,提供了根据key在methon,get、basetype中查找方法的实现,很重要。method、get并没有存在obj_meta,而是存在obj_indexer闭包的上值里。

    它会依次查找methods、getters、arrayindexer(数组)、base(基类)。

     

    register[luaindex][ud] = obj_indexer

    obj_meta[__index]=obj_indexer

    栈中内容:obj_meta,method,get,set

    栈中内容:obj_meta,method,get,set,__newindex,set,csNewIndexer(nil),baseType(nil),register[LuaNewIndexs],arrayNewIndexer(nil)

    LuaAPI.gen_obj_newindexer(L); //设置__newindex方法

    栈中内容:obj_meta,method,get,set,__newindex,closure(xlua.x obj_newindexer)

    register[LuaNewIndexs][ud] = obj_newindexer

    meta[__newindex] = obj_newindexer

    方法执行结束:空栈

    //upvalue --- [1]: methods, [2]:getters, [3]:csindexer, [4]:base, [5]:indexfuncs, [6]:arrayindexer, [7]:baseindex
    //param   --- [1]: obj, [2]: key
    LUA_API int obj_indexer(lua_State *L) {    
       if (!lua_isnil(L, lua_upvalueindex(1))) {
          lua_pushvalue(L, 2);
          lua_gettable(L, lua_upvalueindex(1));
          if (!lua_isnil(L, -1)) {//has method
             return 1;
          }
          lua_pop(L, 1);
       }
       
       if (!lua_isnil(L, lua_upvalueindex(2))) {
          lua_pushvalue(L, 2);
          lua_gettable(L, lua_upvalueindex(2));//get直接调用了,所以lua里get不当做方法处理
          if (!lua_isnil(L, -1)) {//has getter
             lua_pushvalue(L, 1);
             lua_call(L, 1, 1);
             return 1;
          }
          lua_pop(L, 1);
       }
       
       
       if (!lua_isnil(L, lua_upvalueindex(6)) && lua_type(L, 2) == LUA_TNUMBER) {
          lua_pushvalue(L, lua_upvalueindex(6));
          lua_pushvalue(L, 1);
          lua_pushvalue(L, 2);
          lua_call(L, 2, 1);
          return 1;
       }
       
       if (!lua_isnil(L, lua_upvalueindex(3))) {
          lua_pushvalue(L, lua_upvalueindex(3));
          lua_pushvalue(L, 1);
          lua_pushvalue(L, 2);
          lua_call(L, 2, 2);
          if (lua_toboolean(L, -2)) {
             return 1;
          }
          lua_pop(L, 2);
       }
       
       if (!lua_isnil(L, lua_upvalueindex(4))) {
          lua_pushvalue(L, lua_upvalueindex(4));
          while(!lua_isnil(L, -1)) {
             lua_pushvalue(L, -1);
             lua_gettable(L, lua_upvalueindex(5));
             if (!lua_isnil(L, -1)) // found
             {
                lua_replace(L, lua_upvalueindex(7)); //baseindex = indexfuncs[base]
                lua_pop(L, 1);
                break;
             }
             lua_pop(L, 1);
             lua_getfield(L, -1, "BaseType");
             lua_remove(L, -2);
          }
          lua_pushnil(L);
          lua_replace(L, lua_upvalueindex(4));//base = nil
       }
       
       if (!lua_isnil(L, lua_upvalueindex(7))) {
          lua_settop(L, 2);
          lua_pushvalue(L, lua_upvalueindex(7));
          lua_insert(L, 1);
          lua_call(L, 2, 1);
          return 1;
       } else {
          return 0;
       }
    }

    到这边成员meta的内容填充就结束了。

    meta = //LuaAPI.luaL_getmetatable(L, type.FullName) = registry[type.FullName]
    {
            ["__index"] = obj_indexer//(见xlua.c)
            ["__newindex"] = obj_newindexer//(见xlua.c)
            [UserData] = 1
            ["__tostring"] = StaticLuaCallbacks.ToString
            [1] = typeId
    }

    4.BeginClassRegister:生成类的静态(static)元表、静态方法、GetSet的存放表。

    方法结束 栈:cls_table ,meta_table, get, set(-4, -3, -2, -1)

    cls_table[UnderlyingSystemType] = userdata

    cls_meta["__call"] = creator(wrap 的 __CreateInstance,该方法会把ud压栈。

    setmetatable(cls_table, cls_meta)

    static int __CreateInstance(RealStatePtr L)
    {      
        try {
           ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
           if(LuaAPI.lua_gettop(L) == 1)
           {
                UIHierarchy gen_ret = new UIHierarchy();
                translator.Push(L, gen_ret);
                     
                return 1;
           }
        }         
    }

    5.SetCSTable:生成路径表。

    最终实现的是:XLua.LuaDLL.Lua = cls_table

    CS[ud] = cls_table

    6.EndClassRegister:设置类的元表的__index__newindex方法

    方法开始:cls_table, cls_meta,get,set

    :cls_table, cls_meta,get,set,__index,get, cls_table, base(父类), reister["LuaClassIndexs"]

    LuaAPI.gen_cls_indexer(L);//设置__index方法

    :cls_table, cls_meta,get,set,__index,closure(cls_indexer)

    register[LuaClassIndexs][ud] = closure(cls_indexer)

    meta[__index] = closure(cls_indexer)

    :cls_table,cls_meta,get,set

    :cls_table, cls_meta,get,set,__newindex,set, base(父类), reister["LuaClassNewIndexs"]

    LuaAPI.gen_cls_newindexer(L); //设置__newindex方法

    :cls_table, cls_meta,get,set,__newindex,closure(cls_indexer)

    register[LuaClassNewIndexs][ud] = closure(cls_newindexer)

    meta[__newindex] = closure(cls_newindexer)

    方法结束:空

    7.用到的几个lua表:

    1.CLS_IDX对应的cls_table:保存了所有静态方法的引用。

    1.CLS_META_IDX对应的cls_getter:保存了所有get方法的引用,通过cls_meta的__index访问。

    1.CLS_GETTER_IDX对应的cls_setter:保存了所有静态set的引用,通过cls_meta的__newindex访问。

    1.CLS_SETTER_IDX对应的cls_meta:cls_table的元表。

    1.CLS_IDX对应的cls_table:保存了所有静态方法的引用。

    1.CLS_IDX对应的cls_table:保存了所有静态方法的引用。

    五、translator.Push获取typeuserdata,如果没有,则创建,保留userdata在栈顶。

    1. addObject:将object添加到对象池中,创建object-index的映射关系,通过index可以获取到c#对象,而通过c#对象可以获取唯一的index,用于获取对象的ud,从而访问对象的从成员方法。

    public void Push(RealStatePtr L, object o)
            {
                if (o == null)
                {
                    LuaAPI.lua_pushnil(L);
                    return;
                }
    
                int index = -1;
                Type type = o.GetType();
                bool is_enum = type.GetTypeInfo().IsEnum;
                bool is_valuetype = type.GetTypeInfo().IsValueType;
                bool needcache = !is_valuetype || is_enum;
    
                if (needcache && (is_enum ? enumMap.TryGetValue(o, out index) : reverseMap.TryGetValue(o, out index)))
                {
                    //已缓存,通过唯一的typeId取到ud并压栈
                    if (LuaAPI.xlua_tryget_cachedud(L, index, cacheRef) == 1)
                    {
                        return;
                    }
                }
    
                bool is_first;
                int type_id = getTypeId(L, type, out is_first);
    
                if (is_first && needcache && (is_enum ? enumMap.TryGetValue(o, out index) : reverseMap.TryGetValue(o, out index))) 
                {
                    if (LuaAPI.xlua_tryget_cachedud(L, index, cacheRef) == 1)
                    {
                        return;
                    }
                }
    
                index = addObject(o, is_valuetype, is_enum);
                LuaAPI.xlua_pushcsobj(L, index, type_id, needcache, cacheRef);
            }

    2. xlua_pushcsobj:创建一个新的userdata,内容是对象在objects的下标,通过这个下标可以在c#取到对应的对象。

    cacheud:cache [index] = ud

    setmetatable(ud, meta) 设置元表

    也就是说通过translator.Push(L, type)可以获取对象的userdata,这个userdata的元表obj_meta里封装了对该类的所有成员方法、get、set属性的访问方法,我们可以通过该元表的__index、__newindex调用所有wrap内的成员方法、get、set方法。

    static void cacheud(lua_State *L, int key, int cache_ref) {
       lua_rawgeti(L, LUA_REGISTRYINDEX, cache_ref);
       lua_pushvalue(L, -2);
       lua_rawseti(L, -2, key);
       lua_pop(L, 1);
    }
    
    
    LUA_API void xlua_pushcsobj(lua_State *L, int key, int meta_ref, int need_cache, int cache_ref) {
       int* pointer = (int*)lua_newuserdata(L, sizeof(int));
       *pointer = key;
       
       if (need_cache) cacheud(L, key, cache_ref);
    
        lua_rawgeti(L, LUA_REGISTRYINDEX, meta_ref);
    
       lua_setmetatable(L, -2);
    }

    六、总结用到的容器,以及各个meta的内容。

    c

    register[typeId] = meta //typeId是唯一的

    register[type.FullName] = {} 元表是meta,通过LuaAPI.luaL_getmetatable(L, type.FullName);获取到元表

    func_meta = {"__index" = StaticLuaCallbacks.MetaFuncIndex}

    下面这个四个表是用于获取父类的相对应__index方法的。

    translator.Push(L, type == null ? base_type : type.BaseType());实际传到xlua的obj_indexer的是父类的ud,在通过register["LuaIndexs"][ud]获取父类的obj_indexer闭包。

     

    register["LuaIndexs"] = {__index = func_meta}//LuaEnv初始化

    register["LuaNewIndexs"] = {__index = func_meta}//LuaEnv初始化

    register["LuaClassIndexs"] = {__index = func_meta}//LuaEnv初始化

    register["LuaClassNewIndexs"] = {__index = func_meta}//LuaEnv初始化

    register["LuaIndexs"][ud] = obj_indexer(这是个闭包,它的上值包括了这个类的method、set、baseType,实际是__index方法,提供对象查找方法)

    register["LuaNewIndexs"][ud] = obj_newindexer

    register[LuaClassIndexs][ud] = cls_indexer

    register[LuaClassNewIndexs][ud] = cls_newindexer

    register["LuaIndexs"] = {}//元表的__index指向StaticLuaCallbacks.MetaFuncIndex 其他几个类似,luaenv初始化

    cache = register[cacheRef]

    cache [index] = ud (ud = index,元表是typeId对应的meta,即LuaAPI.luaL_getmetatable(L, type.FullName))

    xlua_csharp_namespace = register[xlua_csharp_namespace],在LuaEnv 赋值了 register[xlua_csharp_namespace] = CS,即xlua_csharp_namespace = CS

    CS [path][type.Name] = cls_table //CS.XLua.LuaDLL.Lua = cls_table

    CS [ud] = cls_table


    c#

    typeMap[type_id] = type

    typeIdMap[type] = type_id

    objects[index] = obj //可以试试Type

    reverseMap[obj] = index

    enumMap[obj] = index

    obj_meta = //LuaAPI.luaL_getmetatable(L, type.FullName) = registry[type.FullName]
    {
            ["__index"] = obj_indexer//(见xlua.c)
            ["__newindex"] = obj_newindexer//(见xlua.c)
            [UserData] = 1
            ["__tostring"] = StaticLuaCallbacks.ToString
            [1] = typeId
    }
    
    userdata = index//每个实例都会有一个ud,但是meta是一样的。ud只是用与区别不同的实例,便于在objects中取得对应的实例对象。
    {
            ["__index"] = obj_meta   
    }
    
    cls_meta = //这个是新建的表,是新建的cls_table的元表,用于查找静态的Get方法(包括从基类base查找,静态设置接口)
    {
            ["__call"] = __CreateInstance//(每个类的wrap文件),该方法会把类的ud压栈,而通过这个ud,我们可以访问到类的成员方法。
            ["__index"] = cls_indexer//(见xlua.c)
            ["__newindex"] = cls_newindexer//(见xlua.c)
    }
    
    cls_table = //每个类都会有一个cls_table,可能会有多个ud.这里保存了所有的静态方法映射。
    {
            staticFunc = func
            ["__index"] = cls_meta
    }

    七、静态方法、成员方法的wrap区别。

    如下图所示,成员方法需要调用以下方法取得实例:

    UIHierarchy gen_to_be_invoked = (UIHierarchy)translator.FastGetCSObj(L, 1);

    也就是它的upvalue第一个参数就是对象的实例,对应lua的调用就是冒号调用:UIHierarchy:SetWidgets,而静态方法因为不需要传本身,所以对应lua就是点号调用。

    lua点号和冒号区别:https://www.jianshu.com/p/56961e4bd693

     

    这边的index是对象的ud的内存地址。

    internal object FastGetCSObj(RealStatePtr L,int index)
    {
         return getCsObj(L, index, LuaAPI.xlua_tocsobj_fast(L,index));
    }

    静态方法:直接查询cls_table表,一次查询。

    成员方法:查询ud-查询ud的元表obj_meta-调用obj_meta的_index查询obj_method表。三次查表+一次__index调用。

    总结:尽量封装静态方法给lua使用,性能计较好。

  • 相关阅读:
    parentNode和parentElement区别
    初学canvas,遇到width和height显示问题和用excanvas.js兼容IE问题
    Java学习笔记28(集合框架二:Iterator迭代器)
    Java学习笔记27(集合框架一:ArrayList回顾、Collection接口方法)
    Java学习笔记26(Math类、Arrays类、BigInteger类、BigDecimal类)
    Java学习笔记25(System类)
    Java学习笔记24(Integer类)
    Java学习笔记23(Calendar类)
    Java学习笔记22(Date类、DateFormat类)
    Java学习笔记21(String类补充:正则表达式)
  • 原文地址:https://www.cnblogs.com/wang-jin-fu/p/13508768.html
Copyright © 2011-2022 走看看