ILRuntime跨域继承机制深度解析
跨域继承的概念与意义
在热更新框架ILRuntime中,跨域继承是一个核心功能,它允许热更DLL项目中的代码继承Unity主工程中的类或实现主工程中的接口。这种机制打破了传统C#开发中主工程与热更代码之间的严格界限,为游戏开发提供了极大的灵活性。
跨域继承的实现原理
ILRuntime通过继承适配器(CrossBindingAdaptor)来实现跨域继承。适配器模式在这里起到了桥梁作用,将主工程中的类或接口与热更DLL中的实现连接起来。这种设计既保持了类型安全,又实现了运行时的动态绑定。
适配器实现详解
基本结构
一个完整的跨域继承适配器包含两个主要部分:
- 继承自CrossBindingAdaptor的适配器工厂类
- 实际的适配器实现类
适配器工厂类
工厂类需要实现三个关键属性:
BaseCLRType
: 指定要继承的主工程基类BaseCLRTypes
: 用于实现多个接口(不推荐)AdaptorType
: 返回实际的适配器类型
public class ClassInheritanceAdaptor : CrossBindingAdaptor
{
public override Type BaseCLRType => typeof(ClassInheritanceTest);
public override Type[] BaseCLRTypes => null;
public override Type AdaptorType => typeof(Adaptor);
public override object CreateCLRInstance(AppDomain appdomain, ILTypeInstance instance)
=> new Adaptor(appdomain, instance);
}
实际适配器类
适配器类需要继承目标基类并实现CrossBindingAdaptorType接口:
class Adaptor : ClassInheritanceTest, CrossBindingAdaptorType
{
// 保存ILRuntime相关实例
ILTypeInstance instance;
AppDomain appdomain;
// 缓存方法调用信息
IMethod mTestAbstract;
bool mTestAbstractGot;
// 构造方法
public Adaptor(AppDomain appdomain, ILTypeInstance instance)
{
this.appdomain = appdomain;
this.instance = instance;
}
public ILTypeInstance ILInstance => instance;
}
方法重写的实现技巧
抽象方法实现
对于抽象方法,适配器需要将调用转发到热更代码:
public override void TestAbstract()
{
if(!mTestAbstractGot)
{
mTestAbstract = instance.Type.GetMethod("TestAbstract", 0);
mTestAbstractGot = true;
}
if (mTestAbstract != null)
appdomain.Invoke(mTestAbstract, instance, null);
}
虚方法实现
虚方法的实现需要特别注意循环调用问题:
bool isTestVirtualInvoking = false;
object[] param1 = new object[1]; // 缓存参数数组减少GC
public override void TestVirtual(ClassInheritanceTest a)
{
if (!mTestVirtualGot)
{
mTestVirtual = instance.Type.GetMethod("TestVirtual", 1);
mTestVirtualGot = true;
}
if (mTestVirtual != null && !isTestVirtualInvoking)
{
isTestVirtualInvoking = true;
param1[0] = a;
appdomain.Invoke(mTestVirtual, instance, param1);
isTestVirtualInvoking = false;
}
else
base.TestVirtual(a); // 避免无限递归
}
性能优化建议
- 方法缓存:首次调用时获取方法引用并缓存,避免重复查找
- 参数数组复用:缓存参数数组对象,减少GC压力
- 虚方法调用标志:使用标志位防止递归调用
- 显式传递null:无参数方法调用时显式传递null而非空数组
最佳实践与注意事项
- 避免多重继承:虽然ILRuntime支持一个适配器实现多个接口,但容易引发问题
- 推荐做法:在Unity主工程中创建组合多个接口的基类,然后继承该基类
- 命名规范:保持适配器类命名清晰,如"XXXAdaptor"和"Adaptor"
- 异常处理:考虑在适配器中添加适当的异常处理逻辑
- 性能监控:对于高频调用的方法,需要特别关注性能影响
总结
ILRuntime的跨域继承机制通过适配器模式巧妙地解决了热更代码与主工程之间的类型隔离问题。理解这一机制的工作原理和实现细节,对于开发高效、稳定的热更新功能至关重要。在实际项目中,应当根据具体需求合理设计继承结构,并遵循最佳实践以确保代码的可维护性和运行性能。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考