使用ILRuntime的原因:
参考:https://www.cnblogs.com/decode1234/p/10270911.html
c# 编译成 IL,可以由Mono VM 解释执行 IL,但是Mono实现跨平台,需要针对每个平台进行移植,非常耗时耗力;并且Mono的版权所限,Unity中Mono的版本不是最新的;最重要的是IOS不支持JIT,无法使用Mono,所以使用IL2CPP。
IL2CPP的好处,将IL翻译成C++,由各平台现成的c++编译器编译执行,IL2CPP VM只需要做GC管理。
IL2CPP 翻译C++静态语言,只能AOT编译,不能JIT,不能在运行时编译代码,所以只能将热更代码运行前编译成dll,因此热更的代码不能挂在物体上。
总结
参考:https://ourpalm.github.io/ILRuntime/public/v1/guide/index.html
委托
热更部分调用热更外部的委托,要注册委托
注册委托适配
根据委托签名(参数、返回值)注册,
无返回参数:RegisterMethodDelegate<参数...>
有返回参数:RegisterFunctionDelegate<参数...,返回值>
注册委托转换
非Action、Func类型委托,要注册委托转换,例如Unity的UnityAction、GF的EventHandler<GameFramework.Event.GameEventArgs>
RegisterDelegateConvertor<原委托方法名<参数>>
跨域继承
热更部分继承热更外部的类或实现热更外部接口
热更部分实现多个热更外部接口,支持直接实现多个热更外部接口,但尽量避免使用,可以在热更外部先实现一个类,这个类实现多个接口,热更部分继承这个类。
反射
有区别:
获取Type、创建实例、调用方法、
相同:
设置获取Field、获取Attribute
https://ourpalm.github.io/ILRuntime/public/v1/guide/reflection.html
CLR重定向
原理就是当IL解译器发现需要调用某个指定CLR方法时,将实际调用重定向到另外一个方法进行挟持
可以使用CLR绑定生成的代码修改
CLR绑定:
GenerateCLRBindingByAnalysis
反射效率低,传参object[]有装箱GC
绑定原理使用CLR重定向,调用自定义方法
优化
关闭Development Build
热更DLL编译选择Release或开启代码优化
正式发布的时候可以不加载pdb
少调用可变参数的方法,先获取指定参数个数的方法,把参数压入栈,避免GC
主工程调用热更方式
*appdomain.Invoke
*IMethod method = AppDomain.LoadedTypes["HotfixClass"].GetMethod("Method", ParamsCount) AppDomain.Invoke(method, Params...)
*using (var ctx = GameEntry.ILRuntime.AppDomain.BeginInvoke(m_OnUpdate))
{
ctx.PushFloat(XXX);
ctx.Invoke();
}
具体问题
Enum异常
Test[] arr = (Test[])Enum.GetValues(typeof(Test));
arr[i]获取值异常
断点调试,arr有正确的值,但是无法通过下标取值
Array arr = Enum.GetValues(typeof(Test)) 正常
Enum无法使用CompareTo方法,int类型正常
Test e1 = Test.Five;
Test e2 = Test.One;
e1.CompareTo(e2);