动态加载程序集:为什么这段代码可以工作
本文关键字:代码 工作 段代码 程序集 加载 为什么 动态 | 更新日期: 2023-09-27 18:15:08
在我的情况下有三个组成部分:Consumer
类,IExposedIface
接口和Exposed
类实现IExposedIface
。Consumer
和Exposed
都与IExposedIface
静态链接,但Consumer
没有对Exposed
的编译时引用。
我正试图想出一个方案,允许Consumer
在运行时加载不同版本的Exposed
(取决于输入数据-让我们说每个输入文档携带一个关于应该使用哪个版本的Exposed
来处理它的信息)。为了实现这一点,我开始研究AppDomains,现在我有一个基本的版本工作。
到目前为止,我似乎有两个选择,当它涉及到提供IExposedIface
组装到Exposed
组装。
-
仅在
Consumer
的bin目录中拥有IExposedIface.dll
,并为AppDomain
处理AppDomain.AssemblyResolve
事件,其中我正在创建Exposed
的实例 -
在
Consumer
的bin目录中同时拥有IExposedIface.dll
以及每个Exposed.dll
。
现在考虑我根据IExposedIface
构建Exposed
:
public interface IExposedIface
{
string SaySomething();
}
和我构建Consumer
对IExposedIface
:
public interface IExposedIface
{
string SaySomething();
string SaySomethingDifferent();
}
在第一种情况下,异常
异常:方法'SaySomethingDifferent'在类型'Exposed。暴露的程序集'Exposed, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 没有实现。
在我调用appDomain.CreateInstanceAndUnwrap(...)
在新创建的AppDomain中创建Exposed
的实例时抛出。
我看还算合理。
但是在第二种情况下,appDomain.CreateInstanceAndUnwrap(...)
通过得很好,我可以毫无问题地在检索对象上调用'SaySomething()'方法。一个异常
在接口/类型 'IExposedIface '上找不到'SaySomethingDifferent'方法。IExposedIface, IExposedIface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'.
只在我实际调用Consumer
中的SaySomethingDifferent()
时抛出。
我很惊讶在第二种情况下CLR让我走了这么远…有人能解释一下为什么这是可能的吗?
-
Case #1意味着Exposed.dll绑定到错误版本的IExposedIface.dll -元数据加载器能够在加载程序集时检测到这一点,因为它发现了一个未实现的接口方法。
-
Case #2(可能)意味着除了每个Exposed.dll之外,您还拥有每个IExposedIface.dll的正确版本,因此每个程序集都可以在其自己的AppDomain中加载。但是,AppDomain A的接口与AppDomain B不同,这只有在调用实际跨越AppDomain边界时才会出现问题。
我建议不要尝试那些二进制兼容性游戏,而是做适当的版本控制。用新方法创建一个新接口,继承旧接口,所以IExposedIface.dll的新版本是真正的向后兼容)。其他任何真的很难调试,因为你可能会意外地加载两个版本的IExposedIface.dll(如果它们在windows上可访问),然后你在AppDomain中有两个类型的版本,导致没有结束的麻烦;)