Unity实现c#热更新方案探究(三)
转载请标明出处:http://www.cnblogs.com/zblade/
前面两篇文章从头到尾讲解了C#热更新的一些方案,从程序域来加载和卸载DLL,到使用ILRuntime来实现安卓和IOS平台的DLL热更新。文章二中讲解了ILRuntime对于IL虚拟机在加载DLL的过程中的一些解构。那么今天收尾的文章,就来讲解一下如何基于这个虚拟机实现对于类,方法,属性的调用。
一、基于appDomain来加载类实现反射的调用
对于ILRuntime中的反射,大概可以分为三种类型:一种是ILRuntime运行的DLL中,该程序集中的类之间的反射,这是基于C#的反射,应用无差别; 一种是unity游戏主工程中对DLL中类的反射,这样的反射可以分为两种,一种是获取类,然后直接调用方法, 一种是基于appDomain包装的反射,下面分别举例两种unity主工程对DLL中类的反射,来研究一下如何实现这个过程。
1、基于LoadedTypes来实现反射方法的调用
在ILRuntime中,不能基于System.Type来直接获取热更新DLL中的类,只有基于唯一的appDomain实例,基于LoadedTypes这种来获取热更新中的DLL,基于代码来分析,更为详细:
首先,加载获取该DLL中的指定类:
var it = appDomain.LoadedTypes["HotFix_Project.InstanceClass"]
跟踪LoadedTypes:
public Dictionary<string, IType> LoadedTypes{get{return mapType.InnerDictionary;}}
跟踪看mapType.InnerDictionary:
ThreadSafeDictionary<string, IType> mapType = new ThreadSafeDictionary<string, IType>();
这个mapType是什么时候装配的?
来自于文章二中的LoadAssembly的后续操作:

那么这个module.GetTypes是如何操作的?


分别基于协程来return type以及其nestedTypes,关键是看Types是怎么获取的:

关键是read操作:

继续跟进Read操作:

关键是:
var mtypes = metadata.Types
后续都是对其的封装和填充,对于metadata的填充,来自于InitializeTypeDefinitions这个操作:

关键操作是ReadType这个操作:

构建一个内部定义的类,然后做数据填充,看看关键的几个属性的设置:BaseType ,设置其父类型,fieldsrange/methods_range 是对属性范围和方法范围的设置:

所以基本方法还是ReadListRange:

在这儿,我们最终回到了文章二中对于IL虚拟机中的tableHeap的引用,最后实现了和文章二的首尾呼应。
好了,收起思绪,回到最开始的,获取类,这样获得的一个类,这样得到的一个类,继承自IType,在Unity主工程中,则需要System.Type才能继续使用反射接口,其对于的封装来自昱这个ILType封装的ReflectionType, 其中的ILRuntimeType继承自Type类:

基于其,可以直接调用System.Type的GetConstructor方法,构建实例,归并几个代码,可以表示为(直接使用的实例源代码):
var it = appDomain.LoadedTypes["HotFix_Project.InstanceClass"];
var type = it.ReflectionType;
var ctor = type.GetConstructor(new System.Type[]);
var obj = ctor.Invoke(null);
对应可以得到DLL中该类的构造函数的调用:

2、基于appDomain内嵌的Invoke来实现反射
在ILRuntime中,在appDomain中内嵌了一套Invoke的实现,可以在Unity工程中直接调用来实现对热更新DLL中类的方法的调用:

关键操作就是2步: GetType和 GetMethod,获取类型的过程,和前面有点类似,就是对mapType中存储的获取,如果没有,则进行查找和填充,这儿重点说说方法是如何获取的:

粗看就是从methods中取出来,做相应的检查,如果通过则返回,那么初始化操作看看:

最后还是从definition.Methods中取出,逐个遍历其中的方法做一个分类存储,如果有静态构造函数,且满足对于的参数条件,则执行一次静态构造。
回到开始,在获取到类和方法的相关信息后,就可以执行对于的参数检验,然后执行反射:

可见,就是获取到一个IL的解释器,然后执行相应的反射,具体Run怎么执行,就不继续深入贴图了,有兴趣的可以持续跟踪(基本思路就是对stack的操作,塞入各个参数,然后执行一次操作,塞入结果,然后退回)
对于ILRuntime的反射基本就先研究到这儿,如果要应用到自己的项目中,可以继续深入研究一下代码,看看实现的具体细节。这儿附上开源的相关文档:
二、热更新DLL和Unity主工程的相互调用
基于前面的反射,我们可以基本理出热更DLL和unity主工程的交互本质: 基于IL虚拟机或者.net本身反射来实现交互,对于热更新DLL,其调用unity主工程,则主要是在热更新工程中添加对于unity工程的Assembly-CSharp的引用:

基于这个引用,可以调用其中类的各自方法,举两个类来测试:
一个不继承自MonoBehaviour:

一个继承自MonoBehaviour:

这两个Unity主工程中的类以及其中的方法,在热更新DLL中调用:

可以在Unity主工程中得到输出:

看一下track可以大概了解整个反射的执行过程。
对于Unity执行热更DLL中的调用,就是第一部分的反射实例。
总结:絮絮叨叨的写了三篇文章,算是对最近的研究做一个总结吧,现在项目还在评估这种热更新方案,基于稳妥,以及有基于slua的热更新项目用过,ILRuntime还在评估,其实本质都是相通的:基于自我实现的虚拟机(lua的虚拟机或者IL虚拟机,均基于栈实现),来构建一个自我运行环境,在里面解析执行对于的指令(lua虚拟机的指令/IL语句),来实现对热更新的代码(虽然是以资源方式热更新)。
Unity实现c#热更新方案探究(三)的更多相关文章
- Unity实现c#热更新方案探究(一)
转载请标明出处:http://www.cnblogs.com/zblade/ 最近研究了一下如何在unity中实现c#的热更新,对于整个DLL热更新的过程和方案有一个初步的了解,这儿就写下来,便于后续 ...
- Unity实现c#热更新方案探究(二)
转载请标明出处:http://www.cnblogs.com/zblade/ 一.IOS对DLL热更新的禁止 紧接上文,继续对C#热更新的研究.上文中,已经说了如何基于appDomain来实现对DLL ...
- Unity官方发布热更新方案性能对照
孙广东 2016.3.11 Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda • 什么是热更新 • 为何要热更新 • 怎样在iOS 上对 ...
- Unity代码热更新方案 JSBinding + SharpKit 首页
目前Unity的代码更新方案有很多,主要以lua为主. JSBinding + SharpKit 是一种新的技术,他做了两件事情: JSBinding将C#导出到 JavaScript (引擎是 Mo ...
- unity热更新方案对比
Unity应用的iOS热更新 • 什么是热更新 • 为何要热更新 • 怎样在iOS 上对Unity 应用进行热更新 • 支持Unity iOS 热更新的各种Lua 插件的对照 什么是热更新 • ...
- Unity3D 热更新方案(集合各位专家的汇总)
http://blog.csdn.net/guofeng526/article/details/52662994 热更新”这个词,在Unity3D的应用下,是有些语义错误的,但是作为大家都熟知的一项技 ...
- 腾讯开源手游热更新方案,Unity3D下的Lua编程
原文:http://www.sohu.com/a/123334175_355140 作者|车雄生 编辑|木环 腾讯最近在开源方面的动作不断:先是微信跨平台基础组件Mars宣布开源,腾讯手游又于近期开源 ...
- Unity3D热更新方案网摘总结
参考:http://blog.csdn.net/guofeng526/article/details/52662994 http://blog.csdn.net/u010019717/article/ ...
- 【腾讯Bugly干货分享】手游热更新方案xLua开源:Unity3D下Lua编程解决方案
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/2bY7A6ihK9IMcA0bOFyB-Q 导语 xL ...
随机推荐
- Kilani and the Game-扩散形式的搜索
Kilani and the Game 思路:这种扩散走法的并且有速度.我们需要一层一层的入队, 而且 根据题目要求 按编号处理 例如q1队列中有 1 1 1 2 2 2 2 3 3 3 3 3 3 ...
- <转载>Vim的寄存器(复制黏贴要用)
https://blog.csdn.net/hk2291976/article/details/42196559 消除高亮 :noh
- 我的 FPGA 学习历程(13)—— 电子钟项目
在秒表上一些其他模块就可以变成电子钟了,使用以下约定: 使用 KEY[0] 作为复位按键,复位后显示 00:00. 使用 KEY[1] 作为调整/暂停按键,暂停时电子钟调整的两个灯管保持 1Hz 的频 ...
- webpack4 打包报错 :regeneratorRuntime is not defined
使用async函数,在webpack打包时报错 babel-polyfill is required. You must also install it in order to get async/a ...
- PHP中使用CURL之php curl详细解析
在正式讲怎么用之前啊,先提一句,你得先在你的PHP环境中安装和启用curl模块,具体方式我就不讲了,不同系统不同安装方式,可以google查一下,或者查阅PHP官方的文档,还挺简单的. 1. 拿来先试 ...
- TypeScript专题-Static和使用技巧
class People { static _name: string; print() { //alert(this.name);// 编译不通过,doex not exist on type Pe ...
- 等高布局display:table
display:table用法: 父元素:display:table; 子元素:display:table-cell; 注:使用display:table-cell元素部分出现空白缝隙的问题:设置 . ...
- SVN 问题:None of the environment variables SVN_EDITOR, VISUAL or EDITOR are set, and no 'editor-cmd' run-time
问题原因: 没有设置svn编辑器的环境变量,主要是import.commit中填写comment要用 解决办法: 编辑 /etc/bashrc 文件,加入如下一行: export SVN_EDITOR ...
- postgresql从timestamp(6)复制到timestamp(0),时间会变
主要涉及临界点(跨天) 例子(时间:2016-08-05 23:59:59.863) timestamp(6):2016-08-05 23:59:59.863 timestamp(0):2016-08 ...
- Linux神奇命令之---tar
在生产中会常常用到压缩,解压缩,打包,解包等,这时候tar这个万能的小老弟就是是必不可少的了.linux中最流行的tar是麻雀虽小,五脏俱全,功能强大. tar命令可以为linux的文件和目录创建档案 ...