找回密码
 立即注册
查看: 320|回复: 0

ulua&tolua静态反射

[复制链接]
发表于 2021-8-11 14:33 | 显示全部楼层 |阅读模式
引言:
为了方便在没有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脚本
  1.         print('------------------tolua自带反射测试----------------------')
  2.         --lua自带反射测试
  3.         require 'tolua.reflection'         
  4.     tolua.loadassembly('Assembly-CSharp')        
  5.     --为了省事,全部与一遍
  6.     local bitor = bit.bor(0,1,2,4,8,16,32,64,256,512,1024,2048,4096,8192,16384,32768)
  7.     --上面每个与值的枚举
  8.     --local BindingFlags = require 'System.Reflection.BindingFlags'
  9.     local t = typeof('BoTest2')
  10.     --创建对象
  11.     local obj = tolua.createinstance(t)
  12.     --公有静态方法
  13.     local func = tolua.getmethod(t, 'BoTest2_public_static_int')
  14.     print(func:Call())
  15.     func:Destroy()
  16.     func = nil
  17.     --公有静态带参数方法
  18.     local func = tolua.getmethod(t, 'BoTest2_public_static_int_arg',typeof('System.Int32'))
  19.     print(func:Call(1))
  20.     func:Destroy()
  21.     func = nil
  22.     --公有方法
  23.     local func = tolua.getmethod(t, 'BoTest2_public_int')
  24.     print(func:Call(obj) )
  25.     func:Destroy()
  26.     func = nil
  27.     --公有带参数方法
  28.     local func = tolua.getmethod(t, 'BoTest2_public_int_arg',typeof('System.Int32'))
  29.     print(func:Call(obj,2))
  30.     func:Destroy()
  31.     func = nil
  32.     --私有静态方法
  33.     local func = tolua.gettypemethod(t, 'BoTest2_static_int',bitor)
  34.     print(func:Call())
  35.     func:Destroy()
  36.     func = nil
  37.     --私有方法
  38.     local func = tolua.gettypemethod(t, 'BoTest2_int',bitor)
  39.     print(func:Call(obj))
  40.     func:Destroy()
  41.     func = nil
  42.    
  43.     --公有字段
  44.     local field = tolua.getfield(t, 'public_int')
  45.     field:Set(obj, 5)
  46.     print(field:Get(obj))
  47.     field:Destroy()
  48.     --私有字段
  49.     local field = tolua.getfield(t, 'private_int',bitor)
  50.     field:Set(obj, 6)
  51.     print(field:Get(obj))
  52.     field:Destroy()   
  53.     --公有属性
  54.     local property = tolua.getproperty(t, 'public_int_set_get')
  55.     property:Set(obj, 7, null)
  56.     print(property:Get(obj, null))
  57.     property:Destroy()
  58.     --私有属性
  59.     local property = tolua.getproperty(t, 'private_int_set_get',bitor)
  60.     property:Set(obj, 8, null)
  61.     print(property:Get(obj, null))
  62.     property:Destroy()
  63.     --枚举,这里主要说明枚举怎么用typeof
  64.     local t = typeof('TestEnumOut')
  65.     local t = typeof('BoTest2+TestEnumIn')--这里用 ‘+’来代替‘.’
复制代码
C#脚本
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class BoTest2 {
  5.     //私有变量
  6.     private int private_int;
  7.     public int public_int;
  8.     static int static_int;
  9.     public static int public_static_int;
  10.     private int _public_int_set_get;
  11.     public int public_int_set_get { set { _public_int_set_get = value; } get { return _public_int_set_get; } }
  12.     private int private_int_set_get { set { _public_int_set_get = value; } get { return _public_int_set_get; } }
  13.     //私有方法
  14.     int BoTest2_int()
  15.     {
  16.         Debug.Log("BoTest2_int");
  17.         return 1;
  18.     }
  19.     //私有静态方法
  20.     static int BoTest2_static_int()
  21.     {
  22.         Debug.Log("BoTest2_static_int");
  23.         return 1;
  24.     }
  25.     static int BoTest2_static_int_arg(int arg)
  26.     {
  27.         Debug.Log("BoTest2_static_int_arg");
  28.         Debug.Log("arg:" + arg);
  29.         return 1;
  30.     }
  31.     //公有方法
  32.     public int BoTest2_public_int()
  33.     {
  34.         Debug.Log("BoTest2_public_int");
  35.         return 1;
  36.     }
  37.     public int BoTest2_public_int_arg(int arg)
  38.     {
  39.         Debug.Log("BoTest2_public_int_arg");
  40.         Debug.Log("arg:" + arg);
  41.         return 1;
  42.     }
  43.     //公有静态方法
  44.     public static int BoTest2_public_static_int()
  45.     {
  46.         Debug.Log("BoTest2_public_static_int");
  47.         return 1;
  48.     }
  49.     public static int BoTest2_public_static_int_arg(int arg)
  50.     {
  51.         Debug.Log("BoTest2_public_static_int_arg");
  52.         Debug.Log("arg:" + arg);
  53.         return 1;
  54.     }
  55.     //类内部枚举
  56.     public enum TestEnumIn
  57.            {
  58.                    A,
  59.                    B,
  60.                    C
  61.            }
  62. }
  63. //类外部枚举
  64. public enum TestEnumOut
  65. {
  66.           A,
  67.           B,
  68.           C
  69. }
复制代码
全部的可用方法都能在LuaReflection.cs中找到,如下
  1. public static void OpenLibs(IntPtr L)
  2.         {
  3.             LuaDLL.lua_getglobal(L, "tolua");
  4.             LuaDLL.lua_pushstring(L, "findtype");
  5.             LuaDLL.lua_pushcfunction(L, FindType);
  6.             LuaDLL.lua_rawset(L, -3);
  7.             LuaDLL.lua_pushstring(L, "loadassembly");            
  8.             LuaDLL.tolua_pushcfunction(L, LoadAssembly);
  9.             LuaDLL.lua_rawset(L, -3);
  10.             LuaDLL.lua_pushstring(L, "getmethod");
  11.             LuaDLL.tolua_pushcfunction(L, GetMethod);
  12.             LuaDLL.lua_rawset(L, -3);
  13.             LuaDLL.lua_pushstring(L, "getconstructor");
  14.             LuaDLL.tolua_pushcfunction(L, GetConstructor);
  15.             LuaDLL.lua_rawset(L, -3);
  16.             LuaDLL.lua_pushstring(L, "gettypemethod");
  17.             LuaDLL.tolua_pushcfunction(L, GetTypeMethod);
  18.             LuaDLL.lua_rawset(L, -3);
  19.             LuaDLL.lua_pushstring(L, "getfield");
  20.             LuaDLL.tolua_pushcfunction(L, GetField);
  21.             LuaDLL.lua_rawset(L, -3);
  22.             LuaDLL.lua_pushstring(L, "getproperty");
  23.             LuaDLL.tolua_pushcfunction(L, GetProperty);
  24.             LuaDLL.lua_rawset(L, -3);
  25.             LuaDLL.lua_pushstring(L, "createinstance");
  26.             LuaDLL.tolua_pushcfunction(L, CreateInstance);
  27.             LuaDLL.lua_rawset(L, -3);
  28.             LuaDLL.lua_pop(L, 1);
  29.             LuaState state = LuaState.Get(L);
  30.             state.BeginPreLoad();
  31.             state.AddPreLoad("tolua.reflection", OpenReflectionLibs);            
  32.             state.EndPreLoad();
  33.         }
复制代码
坑点:
1.自己生成了完整的System_TypeWrap.cs,直接使用C#的反射的一些方法,在传参数的时候会有坑,比如lua的number类型,在C# 中是double类型的,如果X方法的参数是int类型,你在调用的时候就会出错!
tolua来处理这个问题的地方列举一个(其他method等也有类似处理!)如下:
可以对比
System_Reflection_FieldInfoWrap.cs的SetValue方法和
LuaField.cs的Set方法
  1. public int Set(IntPtr L)
  2.         {
  3.             try
  4.             {
  5.                 int count = LuaDLL.lua_gettop(L);
  6.                 if (count == 3)
  7.                 {
  8.                     object arg0 = ToLua.CheckVarObject(L, 2, kclass);
  9.                     object arg1 = ToLua.ToVarObject(L, 3);
  10.                     //这里!!!可以对比System_Reflection_FieldInfoWrap.cs的SetValue方法
  11.                     if (arg1 != null) arg1 = TypeChecker.ChangeType(arg1, field.FieldType);
  12.                     field.SetValue(arg0, arg1);
  13.                     return 0;
  14.                 }
  15.                 else if (count == 6)
  16.                 {
  17.                     object arg0 = ToLua.CheckVarObject(L, 2, kclass);
  18.                     object arg1 = ToLua.ToVarObject(L, 3);
  19.                     if (arg1 != null) arg1 = TypeChecker.ChangeType(arg1, field.FieldType);
  20.                     BindingFlags arg2 = (BindingFlags)LuaDLL.luaL_checknumber(L, 4);
  21.                     Binder arg3 = (Binder)ToLua.CheckObject(L, 5, typeof(Binder));
  22.                     CultureInfo arg4 = (CultureInfo)ToLua.CheckObject(L, 6, typeof(CultureInfo));                    
  23.                     field.SetValue(arg0, arg1, arg2, arg3, arg4);
  24.                     return 0;
  25.                 }
  26.                 else
  27.                 {
  28.                     return LuaDLL.luaL_throw(L, "invalid arguments to method: LuaField.Set");
  29.                 }
  30.             }
  31.             catch (Exception e)
  32.             {
  33.                 return LuaDLL.toluaL_exception(L, e);
  34.             }
  35.         }
复制代码
从这里,我猜想,tolua自己封装反射方法的原因很大也是由于这个!所以这里不推荐自己生成完整的System_TypeWrap.cs来做反射的相关功能!
使用技巧
1.对于MonoBehaviour类脚本。一般来言我们可以通过GetComponent(‘脚本名’)获取该脚本的对象,来实现获取改脚本内部变量方法的获取和调用。
2.对于1结合之前的挂载Lua组件LuaComponent特别好用!!!
https://blog.csdn.net/u010314160/article/details/81067750
文中观点,仅限本人理解,若有误,请留言指出!感谢!
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 04:41 , Processed in 0.091145 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表