动态加载程序集:为什么这段代码有效?

发布于 2024-12-17 06:50:52 字数 2032 浏览 0 评论 0原文

在我的情况下,存在三个组件:Consumer 类、IExposedIface 接口和实现IExposedIfaceExpose 类。 ConsumerExposed 均与 IExownedIface 静态链接,但 Consumer 不包含对 的编译时引用暴露

我正在尝试提出一个方案,允许消费者在运行时加载不同版本的暴露(取决于输入数据 - 假设每个输入文档都包含有关哪些信息)应使用 Exposed 版本来处理它)。为了实现这一目标,我开始研究AppDomains,现在我有了一个可以运行的基本版本。

到目前为止,在我看来,在向 Exposited 程序集提供 IExposedIface 程序集时,有两种选择。

  1. 仅在 Consumerbin 目录中拥有 IExposeIface.dll 并处理 AppDomain.AssemblyResolve 事件AppDomain,其中我创建一个 Exposed

    实例,
  2. Consumerbin 目录中以及每个 Exposed.dll 旁边都有 IExposeIface.dll。< /p>

现在考虑一下我针对此 IExposedIface 构建 Exposed

public interface IExposedIface
{
    string SaySomething();    
}

并且针对此 IExposedIface 构建 Consumer

public interface IExposedIface
{
    string SaySomething();
    string SaySomethingDifferent();
}

在第一种情况下, 例外情况

异常:方法“SaySomethingDifferent”位于“Exposed.Expose”类型中 程序集“Exposed,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”没有实现

在我调用 appDomain.CreateInstanceAndUnwrap(...) 在新创建的 AppDomain 中创建 Expose 实例时抛出。

这对我来说看起来很合理。

但在第二种情况下,appDomain.CreateInstanceAndUnwrap(...) 运行得很好,我可以毫无问题地在检索到的对象上调用“SaySomething()”方法。一个例外

在接口/类型上找不到方法“SaySomethingDifferent”“IExposedIface.IExposedIface、IExposedIface、Version=2.0.0.0、Culture=neutral、PublicKeyToken=null”。

仅当我实际在 Consumer 中调用 SaySomethingDifferent() 时才会抛出。

我很惊讶在第二种情况下 CLR 让我走了这么远......有人可以解释为什么这是可能的吗?

In my situation there are three components: Consumer class, IExposedIface interface and Exposed class implementing IExposedIface. Both Consumer and Exposed are linked statically with IExposedIface, but Consumer bears no compile-time reference to Exposed.

I am trying to come up with a scheme which would allow Consumer loading different versions of Exposed at runtime (depending on input data - let's say each input document carries an information about which version of Exposed should be used to process it). To achieve this, I started studying AppDomains and now I have a basic version working.

So far it seems to me there are two options when it comes to providing IExposedIface assembly to Exposed assembly.

  1. Having IExposedIface.dll only in Consumer's bin directory and handling AppDomain.AssemblyResolve event for the AppDomain in which I am creating an instance of Exposed

  2. Having IExposedIface.dll both in Consumer's bin directory as well as aside each Exposed.dll.

Now consider that I build Exposed against this IExposedIface:

public interface IExposedIface
{
    string SaySomething();    
}

and I build Consumer against this IExposedIface:

public interface IExposedIface
{
    string SaySomething();
    string SaySomethingDifferent();
}

In the first case, the exception

Exception: Method 'SaySomethingDifferent' in type 'Exposed.Exposed' from
assembly 'Exposed, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.

is thrown in the moment I call appDomain.CreateInstanceAndUnwrap(...) to create an instance of Exposed in the freshly created AppDomain.

That looks reasonable to me.

But in the second case, appDomain.CreateInstanceAndUnwrap(...) goes through just fine and I can without problems call 'SaySomething()' method on the retrieved object. An exception

The method 'SaySomethingDifferent' was not found on the interface/type 'IExposedIface.IExposedIface, IExposedIface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'.

is only thrown when I actually call SaySomethingDifferent() in Consumer.

I was quite surprised that in this second case CLR had let me go so far...Could someone explain why this is possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深空失忆 2024-12-24 06:50:52
  1. 情况 #1 意味着 Expose.dll 绑定了错误版本的 IExposedIface.dll - 元数据加载器能够在加载程序集时检测到这一点,因为它发现了未实现的接口方法。

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

我建议不要尝试那些二进制兼容性游戏,而是进行适当的版本控制(即使用新方法创建一个新接口,继承旧接口,因此新版本的 IExposeIface.dll 确实向后兼容)。其他任何东西都很难调试,因为如果 Windows 可以访问 IExposeIface.dll 的两个版本,那么您可能会意外加载它们,然后您就有两个版本的 Type在 AppDomain 中造成无穷无尽的麻烦;)

  1. Case #1 means that Exposed.dll is binding against the wrong version of IExposedIface.dll - the metadata loader is able to detect this when loading the assemblies because it finds an unimplemented interface method.

  2. Case #2 (probably) means that you have the correct version of each IExposedIface.dll besides each Exposed.dll so each assembly can load within its own AppDomain. However AppDomain A has a different interface than AppDomain B which is only a problem when the call actually crosses the AppDomain border.

I'd suggest not trying those binary compatibility games and rather do proper versioning (ie. create a new interface with the new methods, inheriting from the old interface, so the new version of IExposedIface.dll is really backwards compatible). Anything else is really hard to debug because you can accidently end up loading both versions of IExposedIface.dll if they are reachable for windows, and then you have two versions of a Type in the AppDomain causing no end of trouble ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文