动态加载程序集:为什么这段代码可以工作

本文关键字:代码 工作 段代码 程序集 加载 为什么 动态 | 更新日期: 2023-09-27 18:15:08

在我的情况下有三个组成部分:Consumer类,IExposedIface接口和Exposed类实现IExposedIfaceConsumerExposed都与IExposedIface静态链接,但Consumer没有对Exposed的编译时引用。

我正试图想出一个方案,允许Consumer在运行时加载不同版本的Exposed(取决于输入数据-让我们说每个输入文档携带一个关于应该使用哪个版本的Exposed来处理它的信息)。为了实现这一点,我开始研究AppDomains,现在我有一个基本的版本工作。

到目前为止,我似乎有两个选择,当它涉及到提供IExposedIface组装到Exposed组装。

  1. 仅在Consumerbin目录中拥有IExposedIface.dll,并为AppDomain处理AppDomain.AssemblyResolve事件,其中我正在创建Exposed的实例

  2. Consumerbin目录中同时拥有IExposedIface.dll以及每个Exposed.dll

现在考虑我根据IExposedIface构建Exposed:

public interface IExposedIface
{
    string SaySomething();    
}

和我构建ConsumerIExposedIface:

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让我走了这么远…有人能解释一下为什么这是可能的吗?

动态加载程序集:为什么这段代码可以工作

  1. Case #1意味着Exposed.dll绑定到错误版本的IExposedIface.dll -元数据加载器能够在加载程序集时检测到这一点,因为它发现了一个未实现的接口方法。

  2. Case #2(可能)意味着除了每个Exposed.dll之外,您还拥有每个IExposedIface.dll的正确版本,因此每个程序集都可以在其自己的AppDomain中加载。但是,AppDomain A的接口与AppDomain B不同,这只有在调用实际跨越AppDomain边界时才会出现问题。

我建议不要尝试那些二进制兼容性游戏,而是做适当的版本控制。用新方法创建一个新接口,继承旧接口,所以IExposedIface.dll的新版本是真正的向后兼容)。其他任何真的很难调试,因为你可能会意外地加载两个版本的IExposedIface.dll(如果它们在windows上可访问),然后你在AppDomain中有两个类型的版本,导致没有结束的麻烦;)