1. 四种程序集加载到上下文及优缺点:
1) 默认加载上下文
加载上下文包含通过探测全局程序集缓存、主机程序集存储区(如果承载运行时)以及应用程序域的 ApplicationBase 和 PrivateBinPath 所找到的程序集。比如Load()使用程序集标识的重载。(探测规则请参见:《(5)CLR 运行时探测程序集引用的步骤》 )
使用默认加载上下文具有以下缺点:
a) 加载到其他上下文中的依赖项不可用。
b) 不能将探测路径外部的位置的程序集加载到默认加载上下文中。
2) 加载位置上下文
可以从未位于应用程序路径下(并因此未包含在探测中)的某个路径加载程序集。加载位置上下文允许从该路径查找和加载依赖项,因为路径信息由上下文维护。
此上下文中的程序集可以使用加载到默认加载上下文中的依赖项。
通过使用 Assembly.LoadFrom 方法或按路径加载的其他方法之一来加载程序集具有以下缺点:
a) 如果已加载一个具有相同标识的程序集,则即使指定了不同的路径,LoadFrom 仍返回已加载的程序集。
b) 如果用 LoadFrom 加载一个程序集,随后默认加载上下文中的一个程序集尝试按显示名称加载同一程序集,则加载尝试将失败。对程序集进行反序列化时,可能发生这种情况。
c) 如果用 LoadFrom 加载一个程序集,并且探测路径包括一个具有相同标识但位置不同的程序集,则会发生切换到默认上下文的情况,这样会有损耗性能。
d) LoadFrom 要求指定路径中包含 FileIOPermissionAccess.Read 和 FileIOPermissionAccess.PathDiscovery 或 WebPermission。
e) 如果存在程序集的本机映像,将不会使用它。
f) 程序集不能以非特定域的方式加载。
3) 只反射上下文
使用 ReflectionOnlyLoad 和 ReflectionOnlyLoadFrom 方法加载的程序集;无法执行这些上下文中的代码。
该上下文通常用于检查无法加载执行的代码,可以
a) 跳过程序集强命名认证。
b) 跳过处理器架构检查规则。
4) 无上下文
在没有上下文的情况下进行加载是将具有同一标识的多个程序集加载到一个应用程序域中的唯一方式。这将省去探测成本。
此上下文中的程序集可以使用加载到默认加载上下文中的依赖项。
a) 使用反射发出生成的瞬态程序集。
b) 从字节数组加载的程序集。(如果加载到的程序集标识(在应用策略后创建的)与全局程序集缓存中的程序集标识匹配,将会从全局程序集缓存加载程序集,这时是加载到“默认加载上下文”中)
c) LoadFile 方法按照目标程序集的文件路径加载该程序集。
在没有上下文的情况下加载程序集具有以下缺点:
a) 无法将其他程序集绑定到在没有上下文的情况下加载的程序集,除非您处理 AppDomain.AssemblyResolve 事件。
b) 不会自动加载依赖项。您可以在没有上下文的情况下预加载依赖项、将依赖项预加载到默认加载上下文中或通过处理 AppDomain.AssemblyResolve 事件来加载依赖项。
c) 在没有上下文的情况下加载具有同一标识的多个程序集会导致出现类型标识问题。
d) 如果存在程序集的本机映像,将不会使用它。
e) 程序集不能以非特定域的方式加载。
2. 避免将一个程序集加载到多个上下文中
将一个程序集加载到多个上下文中会导致出现类型标识问题。将同一个程序集中的相同类型加载到两个不同的上下文中,就像是加载具有相同名称的两个不同的类型一样。如果您尝试将一个类型强制转换为另一个类型,则将引发 InvalidCastException,并显示一条令人混淆的消息,指示不能将类型 MyType 强制转换为类型 MyType(运行时会将这两个程序集副本中的MyType视为不同的类型)。
另:将一个程序集的多个版本加载到同一种上下文中也会导致出现类型标识问题。
3. 考虑切换到默认加载上下文
检查应用程序的程序集加载和部署模式。是否能够消除从字节数组加载的程序集?是否能够将程序集移动到探测路径中?如果程序集位于全局程序集缓存中或应用程序域的探测路径(即 ApplicationBase 和 PrivateBinPath)中,则可以按照程序集的标识来加载程序集。
如果无法将所有程序集放入探测路径中,请考虑替代方式,例如使用 .NET Framework 外接程序模型、将程序集放置到全局程序集缓存中或创建应用程序域。
现在我们已经了解了各种程序集上下文,那么这些上下问和.Net中提供的方法又如何对应呢?请参见: 《(7)动态程序集加载Load()》
《反射机制》系列:
(1)程序集基础知识
(2)强名称程序集与数字证书
(3)程序集加载 Assembly类
(4)绑定程序集配置策略
(5)CLR 运行时探测程序集引用的步骤
(6)程序集加载上下文
(7)动态程序集加载Load()
(8)程序集反射 Type 类
(9)程序集的加载和反射
参考资源:
适用于程序集加载的最佳做法