ILRuntime学习笔记(四)——跨域继承
ILRuntime中跨域继承
1.热更DLL中继承Unity主工程的类型称为跨域继承
2.跨域继承需要编写跨域继承适配器
3.热更DLL不能同时继承或实现1个以上主工程的类型或接口
4.尽量避免跨域继承,尤其避免继承
如果你的类无需引擎提供的各种初始化, 更新及析构, 物理, 渲染等的回调. 最好不要继承MonoBehavior
继承后, 引擎会在事件触发时, 通过反射调用各种函数. 这是需要消耗性能的
主工程:
抽象类TestClassBase:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using ILRuntime.CLR.TypeSystem;
using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Enviorment;
using ILRuntimeDemo;
//下面这行为了取消使用WWW的警告,Unity2018以后推荐使用UnityWebRequest,处于兼容性考虑Demo依然使用WWW
#pragma warning disable CS0618public abstract class TestClassBase
{public virtual int Value{get{return 0;}set{}}public virtual void TestVirtual(string str){Debug.Log("!! TestClassBase.TestVirtual, str = " + str);}public abstract void TestAbstract(int gg);
}
public class Inheritance : MonoBehaviour
{//AppDomain是ILRuntime的入口,最好是在一个单例类中保存,整个游戏全局就一个,这里为了示例方便,每个例子里面都单独做了一个//大家在正式项目中请全局只创建一个AppDomainAppDomain appdomain;System.IO.MemoryStream fs;System.IO.MemoryStream p;void Start(){StartCoroutine(LoadHotFixAssembly());}IEnumerator LoadHotFixAssembly(){//首先实例化ILRuntime的AppDomain,AppDomain是一个应用程序域,每个AppDomain都是一个独立的沙盒appdomain = new ILRuntime.Runtime.Enviorment.AppDomain();//正常项目中应该是自行从其他地方下载dll,或者打包在AssetBundle中读取,平时开发以及为了演示方便直接从StreammingAssets中读取,//正式发布的时候需要大家自行从其他地方读取dll//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//这个DLL文件是直接编译HotFix_Project.sln生成的,已经在项目中设置好输出目录为StreamingAssets,在VS里直接编译即可生成到对应目录,无需手动拷贝//工程目录在Assets\Samples\ILRuntime\1.6\Demo\HotFix_Project~
#if UNITY_ANDROIDWWW www = new WWW(Application.streamingAssetsPath + "/HotFix_Project.dll");
#elseWWW www = new WWW("file:///" + Application.streamingAssetsPath + "/HotFix_Project.dll");
#endifwhile (!www.isDone)yield return null;if (!string.IsNullOrEmpty(www.error))UnityEngine.Debug.LogError(www.error);byte[] dll = www.bytes;www.Dispose();//PDB文件是调试数据库,如需要在日志中显示报错的行号,则必须提供PDB文件,不过由于会额外耗用内存,正式发布时请将PDB去掉,下面LoadAssembly的时候pdb传null即可
#if UNITY_ANDROIDwww = new WWW(Application.streamingAssetsPath + "/HotFix_Project.pdb");
#elsewww = new WWW("file:///" + Application.streamingAssetsPath + "/HotFix_Project.pdb");
#endifwhile (!www.isDone)yield return null;if (!string.IsNullOrEmpty(www.error))UnityEngine.Debug.LogError(www.error);byte[] pdb = www.bytes;fs = new MemoryStream(dll);p = new MemoryStream(pdb);try{appdomain.LoadAssembly(fs, p, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());}catch{Debug.LogError("加载热更DLL失败,请确保已经通过VS打开Assets/Samples/ILRuntime/1.6/Demo/HotFix_Project/HotFix_Project.sln编译过热更DLL");}InitializeILRuntime();OnHotFixLoaded();}void InitializeILRuntime(){
#if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE)//由于Unity的Profiler接口只允许在主线程使用,为了避免出异常,需要告诉ILRuntime主线程的线程ID才能正确将函数运行耗时报告给Profilerappdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
#endif//这里做一些ILRuntime的注册,这里应该写继承适配器的注册,为了演示方便,这个例子写在OnHotFixLoaded了}void OnHotFixLoaded(){Debug.Log("首先我们来创建热更里的类实例");TestClassBase obj;Debug.Log("现在我们来注册适配器, 该适配器由ILRuntime/Generate Cross Binding Adapter菜单命令自动生成");appdomain.RegisterCrossBindingAdaptor(new TestClassBaseAdapter());Debug.Log("现在再来尝试创建一个实例");obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");Debug.Log("现在来调用成员方法");obj.TestAbstract(123);obj.TestVirtual("Hello");obj.Value = 233;Debug.LogFormat("obj.Value={0}", obj.Value);Debug.Log("现在换个方式创建实例");obj = appdomain.Invoke("HotFix_Project.TestInheritance", "NewObject", null, null) as TestClassBase;obj.TestAbstract(456);obj.TestVirtual("Foobar");obj.Value = 2333333;Debug.LogFormat("obj.Value={0}", obj.Value);}void Update(){}private void OnDestroy(){if (fs != null)fs.Close();if (p != null)p.Close();fs = null;p = null;}
}
TestClassBase类的适配器TestClassBaseAdapter :
using System;
using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;namespace ILRuntimeDemo
{ public class TestClassBaseAdapter : CrossBindingAdaptor{static CrossBindingFunctionInfo<System.Int32> mget_Value_0 = new CrossBindingFunctionInfo<System.Int32>("get_Value");static CrossBindingMethodInfo<System.Int32> mset_Value_1 = new CrossBindingMethodInfo<System.Int32>("set_Value");static CrossBindingMethodInfo<System.String> mTestVirtual_2 = new CrossBindingMethodInfo<System.String>("TestVirtual");static CrossBindingMethodInfo<System.Int32> mTestAbstract_3 = new CrossBindingMethodInfo<System.Int32>("TestAbstract");public override Type BaseCLRType{get{return typeof(global::TestClassBase);}}public override Type AdaptorType{get{return typeof(Adapter);}}public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance){return new Adapter(appdomain, instance);}public class Adapter : global::TestClassBase, CrossBindingAdaptorType{ILTypeInstance instance;ILRuntime.Runtime.Enviorment.AppDomain appdomain;public Adapter(){}public Adapter(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance){this.appdomain = appdomain;this.instance = instance;}public ILTypeInstance ILInstance { get { return instance; } }public override void TestVirtual(System.String str){if (mTestVirtual_2.CheckShouldInvokeBase(this.instance))base.TestVirtual(str);elsemTestVirtual_2.Invoke(this.instance, str);}public override void TestAbstract(System.Int32 gg){mTestAbstract_3.Invoke(this.instance, gg);}public override System.Int32 Value{get{if (mget_Value_0.CheckShouldInvokeBase(this.instance))return base.Value;elsereturn mget_Value_0.Invoke(this.instance);}set{if (mset_Value_1.CheckShouldInvokeBase(this.instance))base.Value = value;elsemset_Value_1.Invoke(this.instance, value);}}public override string ToString(){IMethod m = appdomain.ObjectType.GetMethod("ToString", 0);m = instance.Type.GetVirtualMethod(m);if (m == null || m is ILMethod){return instance.ToString();}elsereturn instance.Type.FullName;}}}
}
热更工程:
TestInheritance 类:
using System;
using System.Collections.Generic;namespace HotFix_Project
{//一定要特别注意,:后面只允许有1个Unity主工程的类或者接口,但是可以有随便多少个热更DLL中的接口public class TestInheritance : TestClassBase{public override int Value { get; set; }public override void TestAbstract(int gg){UnityEngine.Debug.Log("!! TestInheritance.TestAbstract gg =" + gg);}public override void TestVirtual(string str){base.TestVirtual(str);UnityEngine.Debug.Log("!! TestInheritance.TestVirtual str =" + str);}public static TestInheritance NewObject(){return new HotFix_Project.TestInheritance();}}
}
生成跨域继承适配器:

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System;
using System.Text;
using System.Collections.Generic;
[System.Reflection.Obfuscation(Exclude = true)]
public class ILRuntimeCrossBinding
{[MenuItem("ILRuntime/生成跨域继承适配器")]static void GenerateCrossbindAdapter(){//由于跨域继承特殊性太多,自动生成无法实现完全无副作用生成,所以这里提供的代码自动生成主要是给大家生成个初始模版,简化大家的工作//大多数情况直接使用自动生成的模版即可,如果遇到问题可以手动去修改生成后的文件,因此这里需要大家自行处理是否覆盖的问题using(System.IO.StreamWriter sw = new System.IO.StreamWriter("Assets/Samples/ILRuntime/2.1.0/Demo/Scripts/Examples/04_Inheritance/InheritanceAdapter.cs")){sw.WriteLine(ILRuntime.Runtime.Enviorment.CrossBindingCodeGenerator.GenerateCrossBindingAdapterCode(typeof(TestClassBase), "ILRuntimeDemo"));}AssetDatabase.Refresh();}
}
#endif
一定要特别注意:后面只允许有1个Unity主工程的类或者接口,但是可以有随便多少个热更DLL中的接口
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
