官方示例下载地址1: https://github.com/Ourpalm/ILRuntime
官方示例下载地址2 : https://github.com/Ourpalm/ILRuntimeU3D
官方文档地址 : https://ourpalm.github.io/ILRuntime/public/v1/guide/tutorial.html
void OnHotFixLoaded()
{
var it = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
Debug.Log("LoadedTypes返回的是IType类型,但是我们需要获得对应的System.Type才能继续使用反射接口");
var type = it.ReflectionType;
var ctor = type.GetConstructor(new System.Type[0]);
var obj = ctor.Invoke(null);
Debug.Log("打印一下结果");
Debug.Log(obj);
Debug.Log("我们试一下用反射给字段赋值");
var fi = type.GetField("id", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
fi.SetValue(obj, 111111);
Debug.Log("我们用反射调用属性检查刚刚的赋值");
var pi = type.GetProperty("ID");
Debug.Log("ID = " + pi.GetValue(obj, null));
}
在热更DLL中使用反射跟原生C#没有任何区别,在主工程中反射热更DLL中的类型均需要通过AppDomain取得
在热更DLL
当中:
//在热更DLL中,以下两种方式均可以
Type t = typeof(TypeName);
Type t2 = Type.GetType("TypeName");
在Unity主工程中:
IType type = appdomain.LoadedTypes["TypeName"];
Type t = type.ReflectedType;
在热更DLL
当中:
Type t = Type.GetType("TypeName");//或者typeof(TypeName)
//以下两种方式均可以
object instance = Activator.CreateInstance(t);
object instance = Activator.CreateInstance();
在Unity主工程中:
object instance = appdomain.Instantiate("TypeName");
在热更DLL
当中:
Type type = typeof(TypeName);
object instance = Activator.CreateInstance(type);
MethodInfo mi = type.GetMethod("foo");
mi.Invoke(instance, null);
在Unity主工程中:
IType t = appdomain.LoadedTypes["TypeName"];
Type type = t.ReflectedType;
object instance = appdomain.Instantiate("TypeName");
//系统反射接口
MethodInfo mi = type.GetMethod("foo");
mi.Invoke(instance, null);
//ILRuntime的接口
IMethod m = t.GetMethod("foo", 0);
appdomain.Invoke(m, instance, null);
都一样:
Type t;
FieldInfo fi = t.GetField("field");
object val = fi.GetValue(instance);
fi.SetValue(instance, val);
Type t;
FieldInfo fi = t.GetField("field");
object[] attributeArr = fi.GetCustomAttributes(typeof(SomeAttribute), false);
在Unity主工程中不能通过new T()的方式来创建热更工程中的类型实例
ILRuntime通过CLR方法绑定机制,可以选择性
的对经常使用的CLR接口进行直接调用,从而尽可能的消除反射调用开销以及额外的GC Alloc
①.找到GenerateCLRBinding方法,将你要被调用的类或者接口加入到Type中 :
public class CLRBindingTestClass
{
public static float DoSomeTest(int a, float b)
{
return a + b;
}
}
static void GenerateCLRBinding()
{
List types = new List();
types.Add(typeof(int));
types.Add(typeof(float));
types.Add(typeof(long));
types.Add(typeof(object));
types.Add(typeof(string));
types.Add(typeof(Array));
types.Add(typeof(Vector2));
types.Add(typeof(Vector3));
types.Add(typeof(Quaternion));
types.Add(typeof(GameObject));
types.Add(typeof(UnityEngine.Object));
types.Add(typeof(Transform));
types.Add(typeof(RectTransform));
types.Add(typeof(CLRBindingTestClass)); //dll要访问的类
types.Add(typeof(Time));
types.Add(typeof(Debug));
types.Add(typeof(Dictionary));
//所有DLL内的类型的真实C#类型都是ILTypeInstance
types.Add(typeof(List));
ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(types, "Assets/ILRuntime/Generated");
}
②.重新生成CLR绑定代码
生成完成可以看到 :
③.测试
ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);
var type = appdomain.LoadedTypes["HotFix_Project.TestCLRBinding"];
var m = type.GetMethod("RunTest", 0);
dll中的RunTest方法:
public static void RunTest()
{
for (int i = 0; i < 100000; i++)
{
CLRBindingTestClass.DoSomeTest(i, i);
}
}
除此之外在ValueTypeBinding案例中演示了另一种方法实现绑定 : 手动编写CLR重定向方法,不过特别麻烦不推荐使用,这里不描述
CLR : 通用语言运行平台(Common Language Runtime)
在反射中我们可以知道一些依赖反射的接口是没有办法直接运行的,最典型的就是在Unity主工程中通过new T()创建热更DLL内类型的实例。ILRuntime为了解决这类问题,引入了CLR重定向机制。 原理就是当IL解译器发现需要调用某个指定CLR方法时,将实际调用重定向到另外一个方法进行挟持,再在这个方法中对ILRuntime的反射的用法进行处理
unsafe void OnHotFixLoaded()
{
foreach (var i in typeof(System.Activator).GetMethods())
{
//找到名字为CreateInstance,并且是泛型方法的方法定义
if (i.Name == "CreateInstance" && i.IsGenericMethodDefinition)
{
appdomain.RegisterCLRMethodRedirection(i, CreateInstance);
}
}
}
public static StackObject* CreateInstance(ILIntepreter intp, StackObject* esp, List
unsafe void OnHotFixLoaded()
{
Debug.Log("下面介绍一个CLR重定向的典型用法,比如我们在DLL里调用Debug.Log,默认情况下是无法显示DLL内堆栈的,像下面这样");
Debug.Log("但是经过CLR重定向之后可以做到输出DLL内堆栈,接下来进行CLR重定向注册");
var mi = typeof(Debug).GetMethod("Log", new System.Type[] { typeof(object) });
appdomain.RegisterCLRMethodRedirection(mi, Log_11);
//这个只是为了演示加的,平时不要这么用,直接在InitializeILRuntime方法里面写CLR重定向注册就行了
Debug.Log("我们再来调用一次刚刚的方法,注意看下一行日志的变化");
appdomain.Invoke("HotFix_Project.TestCLRRedirection", "RunTest", null, null);
}
//编写重定向方法对于刚接触ILRuntime的朋友可能比较困难,比较简单的方式是通过CLR绑定生成绑定代码,然后在这个基础上改,比如下面这个代码是从UnityEngine_Debug_Binding里面复制来改的
//如何使用CLR绑定请看相关教程和文档
unsafe static StackObject* Log_11(ILIntepreter __intp, StackObject* __esp, IList