前文中我们提到做U8二开的时候,需要在工程中手工引用各模块依赖的Net程序集DLL文件,包括这些dll依赖的间接程序集,往往最后是越引用越多,程序越来越大,而且版本冲突的可能性越大。况且U8安装目录下100多个文件夹,同名的库有不同的版本和大小,这对于一个大型软件体来说,再正常不过了。如何自定义控制程序的装载路径,加载程序集的不同版本,以及动态装载程序集是本文要讨论的话题。
开始介绍U8的二次开发动态加载程序集功能之前,先来了解一些基础知识,文末将提供对应的源代码示例包。
解析程序集加载
做过开发的同学都知道,常规情况下,应用依赖的dll文件或者第三方库,要么都放在bin目录中,要么都放到和exe平级的目录下,或者全局共享目录GAC中,有时候还得放点东西到Windows目录下。其实这些都是Net平台加载dll常规探测路径之一,属于默认行为,当在这些目录找不到当前运行程序引用的程序集时,就会异常并提示错误:未能加载****版本程序集文件。我们也见怪不怪了,提示啥dll缺失,就去找对应版本的dll文件,拷贝到当前运行目录,多半就能正常运行了。但是有时候遇到版本强签名或者版本不匹配就呜呼了。
其实Net平台提供了API让开发人员可以自行控制程序集探测路径,如此就方便灵活了很多,还可以带来不少好处,原文如下:
.NET 为对程序集加载需要更强控制的应用程序提供了 AppDomain.AssemblyResolve 事件。 通过处理此事件,应用程序可从常规探测路径外部将程序集加载到加载上下文、从几个程序集版本中选择要加载的版本、发出动态程序集并返回此程序集,等等。 本主题指导如何处理 AssemblyResolve 事件。
基本原理是响应特殊的委托事件,即注册 AssemblyResolve 事件的处理程序后,每当程序运行时无法按名称绑定到程序集时,此处理程序都将被调用。
//当程序集(Assembly)通过反射加载失败的时候会触发AssemblyResolve事件,这里注册AssemblyResolve事件的处理函数为CurrentDomain_AssemblyResolve
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
//当类型(Type)通过反射加载失败的时候会触发TypeResolve事件,这里注册TypeResolve事件的处理函数为CurrentDomain_TypeResolve
AppDomain.CurrentDomain.TypeResolve += Curren