ulua&tolua静态反射

引言:
为了方便在没有wrap的情况下,fix c#的一些bug,在不能使用动态反射的情况下(ios不支持,具体不支持哪些API,我也不知道~~尴尬!),只好研究下tolua的静态反射功能。以下提到的反射,均为静态反射。
正文:
接下来会从几个方面来写这篇文章
1.tolua导出的System_TypeWrap.cs中为什么没有GetMethod等一系列反射方法?
解释:
1)既然没有,怎么生成?
打开ToLua_System_Type.cs脚本,可以看到很多[NoToLuaAttribute]修饰的方法。[NoToLuaAttribute]这个特性是用来屏蔽导出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
文中观点,仅限本人理解,若有误,请留言指出!感谢!

你可能感兴趣的:(Lua/Tolua/Xlua)