Assembly.Load(byte[])是如何工作的?

3

我想知道如果在web应用程序中加载相同的程序集字节会发生什么情况。

例如,我有以下代码:

byte[] assem = System.IO.File.ReadAllBytes(appRoot + "/Plugins/Plugin.dll");

var loadedAssem = Assembly.Load(assem);

var plugin = loadedAssem.CreateInstance("Plugin.ThePlugin") as IPlugin;

我运行了这段代码,在第一次请求时,我认为它会将程序集加载到内存中(或者是HTTP运行时应用程序域?),然后我可以创建其中的任何实例。
如果我再次运行此代码,比如在第二个请求中,第一个请求中的程序集会发生什么?
它仍然存在于内存中吗?如果是这样,它如何区分两个程序集?还是它覆盖先前声明的类?
这是为了我理解,就像我在PHP中所做的那样,这不仅仅是“require_once”的情况。
1个回答

7
这将加载两个不同的程序集,每个程序集都可以从您的应用程序中使用。每个程序集中的类型都是独立的类型,彼此之间不会互操作。例如,如果您从Copy1中取出一个Widget并尝试将其传递给在Copy2上接受Widget的方法,这将导致运行时失败。一旦以这种方式加载程序集(即到您的主AppDomain),就无法卸载它们。

关于实例化:

  • 如果您使用 Assembly.CreateInstance(如您的帖子中所示),则将从您用于调用的程序集实例创建它。
  • 如果您使用一个带有字符串参数的 Activator.CreateInstance,您需要指定程序集名称。在这种情况下,由于两个已加载的程序集具有相同的名称,因此它将使用程序集解析规则,默认情况下我认为会优先选择第一个匹配项(因此是您最先加载的程序集)。我不确定这一点。您可以挂钩 AppDomain.AssemblyResolve 事件来提供自己的优先级并使其使用您最近加载的程序集。

我明白了,当你说它们是不同的时候,如果我加载了两个相同程序集的副本并创建了一个类实例,比如Widget..那么这个类会从哪个程序集中实例化? - Richard Adnams
是的...我刚才真的问了那个问题吗?已经很晚了...我应该睡觉了,哈哈。好的,如果我有这两个拷贝已经被加载了,而我只需要使用其中一个并卸载另一个,那么我需要将它们加载到一个单独的应用程序域中,然后卸载该域吗? - Richard Adnams
@Richard,是的,但这并不像听起来的那么容易。如果你想了解更多关于AppDomains的内容,请阅读MarshalByRefObject、透明代理和AppDomain隔离的相关知识。在允许隔离方面有很多微妙之处。如果您不经常重新加载,最简单的方法是只加载一个副本。此外,如果您是Web应用程序,则您的主要AppDomain可能经常被卸载(不确定您的设置方式)。 - Dan Bryant
@DanBryant 好的,我会再多了解一下。另外,进行跨应用程序域调用是否会影响性能?如果有影响,有没有避免的方法? - Richard Adnams
@Richard,跨域调用是通过代理进行的,因此肯定会有性能损失。跨越域边界的引用对象必须派生自MarshalByRefObject,并且您应该将它们视为远程对象。所有其他对象必须是可序列化的,然后将通过值进行编组(使用序列化创建副本)。为了处理这种开销,您需要遵循设计进程间远程解决方案时采用的相同类型的实践,即最小化所需的编组。 - Dan Bryant
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接