引言:
为了方便在没有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
文中观点,仅限本人理解,若有误,请留言指出!感谢!