• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Lua调用c#发生了什么?

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

目录: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使用,性能计较好。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
在Windows环境下构建Lua入门发布时间:2022-07-22
下一篇:
skynet源码分析之网络层——Lua层介绍发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap