03 调试、委托、继承
ILRuntime断点调试
VS有官方插件可以支持,我这边说一下怎么用Rider进行调试
(待补充)
使用委托
如果一个委托在热更中定义,并且被热更中的方法调用,那么我们可以直接调用这个方法,不需要额外处理
如果在主工程中定义了委托,但想要在热更中进行操作,那么需要有适配器以及转换器
如有以下主工程代码
public delegate void TestDelegateMethod(int a);
public delegate string TestDelegateFunction(int a);
public class DelegateDemo : MonoBehaviour
{
    public static TestDelegateMethod TestMethodDelegate;
    public static TestDelegateFunction TestFunctionDelegate;
    public static System.Action<string> TestActionDelegate;
}
有以下热更代码
public class TestDelegate
{
    public static void Initialize2()
    {
        DelegateDemo.TestMethodDelegate = Method;
        DelegateDemo.TestFunctionDelegate = Function;
        DelegateDemo.TestActionDelegate = Action;
    }
    
	static void Method(int a)
	{
		UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
	}
	static string Function(int a)
	{
		return a.ToString();
	}	
	static void Action(string a)
	{
		UnityEngine.Debug.Log("!! TestDelegate.Action, a = " + a);
	}
}
- 
适配器由于主工程中定义的委托完全没有被使用,那么当使用IL2CPP编译时,可能导致代码直接被优化(删了),从而引发报错,因此我们必须象征性的提前注册以下相关委托(象征性的使用以下) //TestDelegateMethod, 这个委托类型为有个参数为int的方法,注册仅需要注册不同的参数搭配即可 appdomain.DelegateManager.RegisterMethodDelegate<int>(); //带返回值的委托的话需要用RegisterFunctionDelegate,返回类型为最后一个 appdomain.DelegateManager.RegisterFunctionDelegate<int, string>(); //Action<string> 的参数为一个string appdomain.DelegateManager.RegisterMethodDelegate<string>();注意,并不是每一个委托对应一个适配器,而是每一个类型组合对应一个适配器 
- 
转换器在ILRT的内部,所有的委托均采用Action和Func进行存储,这和我们自定义为的委托显然是不一样的, 因此我们必须提供一个转换器,可以把对应的委托转换成ILRT支持的类型,如果你的委托就是Action或者Func类型,那不需要转换器,原因在于当我们注册适配器时,ILRT就会自动注册转换器了 appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) => { //转换器的目的是把Action或者Func转换成正确的类型,这里则是把Action<int>转换成TestDelegateMethod return new TestDelegateMethod((a) => { //调用委托实例 ((System.Action<int>)action)(a); }); }); //对于TestDelegateFunction同理,只是是将Func<int, string>转换成TestDelegateFunction appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) => { return new TestDelegateFunction((a) => { return ((System.Func<int, string>)action)(a); }); }); //下面再举一个这个Demo中没有用到,但是UGUI经常遇到的一个委托,例如UnityAction<float> appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<float>>((action) => { return new UnityEngine.Events.UnityAction<float>((a) => { ((System.Action<float>)action)(a); }); });看一下关于转换器注册的源码 public void RegisterDelegateConvertor<T>(Func<Delegate, Delegate> action) { var type = typeof(T); if (type.IsSubclassOf(typeof(Delegate))) { clrDelegates[type] = action; } else throw new NotSupportedException(); }参数是一个Func委托,其参数是一个委托,返回值也是一个委托,emmm,有转换器内味了是吧 再观察我们的转换过程,最终是return了一个new的目标委托类型,而这个委托中所需要执行的方法,则来自于Func中的参数,我们先转成目标Action,再执行 

继承
当想在热更中继承主工程的类时,依然需要一个适配器
在主工程有如下类
public 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);
}
则需要进行适配器的注册
appdomain.RegisterCrossBindingAdaptor(new TestClassBaseAdapter());
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)
        {
            // 如果热更中调用了base.TestVirtual();
            if (mTestVirtual_2.CheckShouldInvokeBase(this.instance))
                base.TestVirtual(str);
            else
                mTestVirtual_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;
                else
                    return mget_Value_0.Invoke(this.instance);
            }
            set
            {
                if (mset_Value_1.CheckShouldInvokeBase(this.instance))
                    base.Value = value;
                else
                    mset_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();
            }
            else
                return instance.Type.FullName;
        }
    }
}
真正的适配过程都在Adapter中,不难发现只是将所有的方法都转到了目标方法上
这个类可以通过ILRT提供的工具方法自动生成

但我们得提前写入所需类型到对应位置

 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号