APSchmidt 发表于 2021-8-11 14:33

ulua&tolua静态反射

引言:
为了方便在没有wrap的情况下,fix c#的一些bug,在不能使用动态反射的情况下(ios不支持,具体不支持哪些API,我也不知道~~尴尬!),只好研究下tolua的静态反射功能。以下提到的反射,均为静态反射。
正文:
接下来会从几个方面来写这篇文章
1.tolua导出的System_TypeWrap.cs中为什么没有GetMethod等一系列反射方法?
解释:
1)既然没有,怎么生成?
打开ToLua_System_Type.cs脚本,可以看到很多修饰的方法。这个特性是用来屏蔽导出wrap的,删除(注释)后,再次点击unity菜单栏 lua菜单的Gen BaseType ,可重新生成完整的System_TypeWrap.cs
2)为什么会屏蔽?
tolua自己封装了一套相对更优(查找速度?)的反射方法组,在Tolua/Reflection/目录下的
LuaConstructor.cs、LuaField.cs、LuaMethod.cs、LuaProperty.cs、LuaReflection.cs
2.怎么使用?
ToLua/Examples/22_Reflection 的示例中,已经演示了大部分的使用方法,参见TestReflection.cs
对于私有的一些东西,示例中没有说明。这里补充一下
lua脚本
        print('------------------tolua自带反射测试----------------------')
        --lua自带反射测试
        require 'tolua.reflection'         
    tolua.loadassembly('Assembly-CSharp')      
    --为了省事,全部与一遍
    local bitor = bit.bor(0,1,2,4,8,16,32,64,256,512,1024,2048,4096,8192,16384,32768)
    --上面每个与值的枚举
    --local BindingFlags = require 'System.Reflection.BindingFlags'
    local t = typeof('BoTest2')
    --创建对象
    local obj = tolua.createinstance(t)
    --公有静态方法
    local func = tolua.getmethod(t, 'BoTest2_public_static_int')
    print(func:Call())
    func:Destroy()
    func = nil
    --公有静态带参数方法
    local func = tolua.getmethod(t, 'BoTest2_public_static_int_arg',typeof('System.Int32'))
    print(func:Call(1))
    func:Destroy()
    func = nil
    --公有方法
    local func = tolua.getmethod(t, 'BoTest2_public_int')
    print(func:Call(obj) )
    func:Destroy()
    func = nil
    --公有带参数方法
    local func = tolua.getmethod(t, 'BoTest2_public_int_arg',typeof('System.Int32'))
    print(func:Call(obj,2))
    func:Destroy()
    func = nil
    --私有静态方法
    local func = tolua.gettypemethod(t, 'BoTest2_static_int',bitor)
    print(func:Call())
    func:Destroy()
    func = nil
    --私有方法
    local func = tolua.gettypemethod(t, 'BoTest2_int',bitor)
    print(func:Call(obj))
    func:Destroy()
    func = nil
   
    --公有字段
    local field = tolua.getfield(t, 'public_int')
    field:Set(obj, 5)
    print(field:Get(obj))
    field:Destroy()
    --私有字段
    local field = tolua.getfield(t, 'private_int',bitor)
    field:Set(obj, 6)
    print(field:Get(obj))
    field:Destroy()   
    --公有属性
    local property = tolua.getproperty(t, 'public_int_set_get')
    property:Set(obj, 7, null)
    print(property:Get(obj, null))
    property:Destroy()
    --私有属性
    local property = tolua.getproperty(t, 'private_int_set_get',bitor)
    property:Set(obj, 8, null)
    print(property:Get(obj, null))
    property:Destroy()
    --枚举,这里主要说明枚举怎么用typeof
    local t = typeof('TestEnumOut')
    local t = typeof('BoTest2+TestEnumIn')--这里用 ‘+’来代替‘.’C#脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BoTest2 {
    //私有变量
    private int private_int;
    public int public_int;
    static int static_int;
    public static int public_static_int;

    private int _public_int_set_get;
    public int public_int_set_get { set { _public_int_set_get = value; } get { return _public_int_set_get; } }

    private int private_int_set_get { set { _public_int_set_get = value; } get { return _public_int_set_get; } }

    //私有方法
    int BoTest2_int()
    {
      Debug.Log("BoTest2_int");
      return 1;
    }

    //私有静态方法
    static int BoTest2_static_int()
    {
      Debug.Log("BoTest2_static_int");
      return 1;
    }
    static int BoTest2_static_int_arg(int arg)
    {
      Debug.Log("BoTest2_static_int_arg");
      Debug.Log("arg:" + arg);
      return 1;
    }
    //公有方法
    public int BoTest2_public_int()
    {
      Debug.Log("BoTest2_public_int");
      return 1;
    }
    public int BoTest2_public_int_arg(int arg)
    {
      Debug.Log("BoTest2_public_int_arg");
      Debug.Log("arg:" + arg);
      return 1;
    }
    //公有静态方法

    public static int BoTest2_public_static_int()
    {
      Debug.Log("BoTest2_public_static_int");
      return 1;
    }
    public static int BoTest2_public_static_int_arg(int arg)
    {
      Debug.Log("BoTest2_public_static_int_arg");
      Debug.Log("arg:" + arg);
      return 1;
    }
    //类内部枚举
    public enum TestEnumIn
           {
                   A,
                   B,
                   C
           }
}

//类外部枚举
public enum TestEnumOut
{
        A,
        B,
        C
}
全部的可用方法都能在LuaReflection.cs中找到,如下
public static void OpenLibs(IntPtr L)
      {
            LuaDLL.lua_getglobal(L, "tolua");

            LuaDLL.lua_pushstring(L, "findtype");
            LuaDLL.lua_pushcfunction(L, FindType);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pushstring(L, "loadassembly");            
            LuaDLL.tolua_pushcfunction(L, LoadAssembly);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pushstring(L, "getmethod");
            LuaDLL.tolua_pushcfunction(L, GetMethod);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pushstring(L, "getconstructor");
            LuaDLL.tolua_pushcfunction(L, GetConstructor);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pushstring(L, "gettypemethod");
            LuaDLL.tolua_pushcfunction(L, GetTypeMethod);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pushstring(L, "getfield");
            LuaDLL.tolua_pushcfunction(L, GetField);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pushstring(L, "getproperty");
            LuaDLL.tolua_pushcfunction(L, GetProperty);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pushstring(L, "createinstance");
            LuaDLL.tolua_pushcfunction(L, CreateInstance);
            LuaDLL.lua_rawset(L, -3);

            LuaDLL.lua_pop(L, 1);

            LuaState state = LuaState.Get(L);
            state.BeginPreLoad();
            state.AddPreLoad("tolua.reflection", OpenReflectionLibs);            
            state.EndPreLoad();
      }坑点:
1.自己生成了完整的System_TypeWrap.cs,直接使用C#的反射的一些方法,在传参数的时候会有坑,比如lua的number类型,在C# 中是double类型的,如果X方法的参数是int类型,你在调用的时候就会出错!
tolua来处理这个问题的地方列举一个(其他method等也有类似处理!)如下:
可以对比
System_Reflection_FieldInfoWrap.cs的SetValue方法和
LuaField.cs的Set方法
public int Set(IntPtr L)
      {
            try
            {
                int count = LuaDLL.lua_gettop(L);

                if (count == 3)
                {
                  object arg0 = ToLua.CheckVarObject(L, 2, kclass);
                  object arg1 = ToLua.ToVarObject(L, 3);
                  //这里!!!可以对比System_Reflection_FieldInfoWrap.cs的SetValue方法
                  if (arg1 != null) arg1 = TypeChecker.ChangeType(arg1, field.FieldType);
                  field.SetValue(arg0, arg1);
                  return 0;
                }
                else if (count == 6)
                {
                  object arg0 = ToLua.CheckVarObject(L, 2, kclass);
                  object arg1 = ToLua.ToVarObject(L, 3);
                  if (arg1 != null) arg1 = TypeChecker.ChangeType(arg1, field.FieldType);
                  BindingFlags arg2 = (BindingFlags)LuaDLL.luaL_checknumber(L, 4);
                  Binder arg3 = (Binder)ToLua.CheckObject(L, 5, typeof(Binder));
                  CultureInfo arg4 = (CultureInfo)ToLua.CheckObject(L, 6, typeof(CultureInfo));                  
                  field.SetValue(arg0, arg1, arg2, arg3, arg4);
                  return 0;
                }
                else
                {
                  return LuaDLL.luaL_throw(L, "invalid arguments to method: LuaField.Set");
                }
            }
            catch (Exception e)
            {
                return LuaDLL.toluaL_exception(L, e);
            }
      }从这里,我猜想,tolua自己封装反射方法的原因很大也是由于这个!所以这里不推荐自己生成完整的System_TypeWrap.cs来做反射的相关功能!
使用技巧
1.对于MonoBehaviour类脚本。一般来言我们可以通过GetComponent(‘脚本名’)获取该脚本的对象,来实现获取改脚本内部变量方法的获取和调用。
2.对于1结合之前的挂载Lua组件LuaComponent特别好用!!!
https://blog.csdn.net/u010314160/article/details/81067750
文中观点,仅限本人理解,若有误,请留言指出!感谢!
页: [1]
查看完整版本: ulua&tolua静态反射