ILRuntime第三课Delegate

​1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using  System.Collections;
using  System.Collections.Generic;
using  UnityEngine;
using  ILRuntime.Runtime.Enviorment;
using  System.IO;
using  ILRuntime.CLR.Method;
 
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;
 
     //AppDomain是ILRuntime的入口,最好是在一个单例类中保存,整个游戏全局就一个,这里为了示例方便,每个例子里面都单独做了一个
     //大家在正式项目中请全局只创建一个AppDomain
     AppDomain appdomain;
 
     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里直接编译即可生成到对应目录,无需手动拷贝
#if UNITY_ANDROID
         WWW www =  new  WWW(Application.streamingAssetsPath +  "/HotFix_TestProject.dll" );
#else
         WWW www =  new  WWW( "file:///"  + Application.streamingAssetsPath +  "/HotFix_TestProject.dll" );
#endif
         while  (!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_ANDROID
         www =  new  WWW(Application.streamingAssetsPath +  "/HotFix_TestProject.pdb" );
#else
         www =  new  WWW( "file:///"  + Application.streamingAssetsPath +  "/HotFix_TestProject.pdb" );
#endif
         while  (!www.isDone)
             yield  return  null ;
         if  (! string .IsNullOrEmpty(www.error))
             UnityEngine.Debug.LogError(www.error);
         byte [] pdb = www.bytes;
         using  (System.IO.MemoryStream fs =  new  MemoryStream(dll))
         {
             using  (System.IO.MemoryStream p =  new  MemoryStream(pdb))
             {
                 appdomain.LoadAssembly(fs, p,  new  Mono.Cecil.Pdb.PdbReaderProvider());
             }
         }
 
         InitializeILRuntime();
         OnHotFixLoaded();
     }
 
     void  InitializeILRuntime()
     {
         //下面这些注册代码,正式使用的时候,应该写在InitializeILRuntime中
         //TestDelegateMethod, 这个委托类型为有个参数为int的方法,注册仅需要注册不同的参数搭配即可
         appdomain.DelegateManager.RegisterMethodDelegate< int >();
         //带返回值的委托的话需要用RegisterFunctionDelegate,返回类型为最后一个
         appdomain.DelegateManager.RegisterFunctionDelegate< int string >();
         //Action<string> 的参数为一个string
         appdomain.DelegateManager.RegisterMethodDelegate< string >();
 
         //TestDelegateMethod委托转换器
         appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((act) =>
         {
             return  new  TestDelegateMethod((a) =>
             {
                 ((System.Action< int >)act)(a);
             });
         });
 
         appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((act) =>
         {
             return  new  TestDelegateFunction((a) =>
             {
                 return  ((System.Func< int , string >)act)(a);
             });
         });
 
 
     }
 
     void  OnHotFixLoaded() {
         Debug.Log( "完全在热更DLL内部使用的委托,直接可用,不需要做任何处理" );
         appdomain.Invoke( "HotFix_TestProject.DelegateTest" "Initialize" , null , null );
         appdomain.Invoke( "HotFix_TestProject.DelegateTest" "RunTest" null , null );
 
         Debug.Log( "如果需要跨域调用委托(将热更DLL里面的委托实例传到Unity主工程用), 就需要注册适配器,不然就会像下面这样" );
 
         try  {
             //适配器错误会消失,因为在InitializeILRuntime中写了委托适配器,但是会报转换器的错误
             appdomain.Invoke( "HotFix_TestProject.DelegateTest" "Initialize2" null null );
             appdomain.Invoke( "HotFix_TestProject.DelegateTest" "RunTest2" null null );
         }
         catch  (System.Exception ex) {
             Debug.LogError(ex.ToString());
         }
 
         //为了演示,清除适配器缓存,实际使用中不要这么做
         //ClearDelegateCache();
         //Debug.Log("这是因为iOS的IL2CPP模式下,不能动态生成类型,为了避免出现不可预知的问题,我们没有通过反射的方式创建委托实例,因此需要手动进行一些注册");
         //Debug.Log("首先需要注册委托适配器,刚刚的报错的错误提示中,有提示需要的注册代码");
         //Debug.Log("ILRuntime内部是用Action和Func这两个系统内置的委托类型来创建实例的,所以其他的委托类型都需要写转换器");
         //Debug.Log("将Action或者Func转换成目标委托类型");
 
         Debug.Log( "我们再来在Unity主工程中调用一下刚刚的委托试试" );
         TestMethodDelegate(789);
         var  str = TestFunctionDelegate(098);
         Debug.Log( "!! OnHotFixLoaded str = "  + str);
         TestActionDelegate( "Hello From Unity Main Project" );
 
     }
 
     void  ClearDelegateCache() {
         var  type = appdomain.LoadedTypes[ "HotFix_TestProject.DelegateTest" ];
         ILMethod m = type.GetMethod( "Method" , 1)  as  ILMethod;
         m.DelegateAdapter =  null ;
 
         m = type.GetMethod( "Function" , 1)  as  ILMethod;
         m.DelegateAdapter =  null ;
 
         m = type.GetMethod( "Action" , 1)  as  ILMethod;
         m.DelegateAdapter =  null ;
     }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值