C# Assembly.Load与Assembly.ReflectionOnlyLoad的区别

49

我正试图理解Assembly.Load和Assembly.ReflectionOnlyLoad之间的区别。

在下面的代码中,我试图找到给定程序集中从给定接口继承的所有对象:

var myTypes = new List<Type>();

var assembly = Assembly.Load("MyProject.Components");

foreach (var type in assembly.GetTypes())
{
   if (type.GetInterfaces().Contains(typeof(ISuperInterface)))
   {
      myTypes.Add(type);
   }
}
这段代码对我来说很好用,但我正在研究其他可能更好的替代方法,并了解到Assembly.ReflectionOnlyLoad()方法。
我认为,由于我没有加载或执行任何对象,基本上只是查询其定义,所以我可以使用ReflectionOnlyLoad来稍微提高性能...
但事实证明,当我将Assembly.Load更改为Assembly.ReflectionOnlyLoad时,当它调用assembly.GetTypes()时会出现以下错误:
System.Reflection.ReflectionTypeLoadException:

无法加载一个或多个所请求的类型。检索LoaderExceptions属性以获取更多信息。

5个回答

28
根据Jon的回复,了解LoaderExceptions中有什么内容将会很有帮助。缺乏这个信息的情况下,我想我可以猜测一下。根据 MSDN 上的说明:

如果程序集依赖于其他程序集,则ReflectionOnlyLoad方法不会加载这些程序集。如果您需要检查它们,则必须自行加载。

您需要附加一个处理程序到 AppDomain.ReflectionOnlyAssemblyResolve 来帮助CLR加载要加载的程序集的任何依赖项。您是否已经这样做了?

11
ReflectionOnly方法是你可以在不遵循通常的Load/LoadFrom规则的情况下,加载特定磁盘上的程序集以进行检查的唯一方式。例如,你可以使用与GAC中相同标识的基于磁盘的程序集进行加载。如果你尝试使用LoadFrom或LoadFile进行此操作,那么GAC程序集将始终被加载。
此外,你不能在返回的Assembly实例上调用GetCustomAttributes(...),因为这将尝试实例化程序集中的Attributes,它们是ReflectionOnly的。你必须使用CustomAttributeData类的静态方法来完成此操作。
通过ReflectionOnly加载的程序集中不得实例化任何类型。

10

我相信你对Load和ReflectionOnlyLoad之间的区别有一个通用的理解。问题在于,即使只是简单地加载一个类型,CLR也需要读取该类型所定义的程序集中的元数据,并且要加载每个定义该类型祖先的程序集中的元数据。因此,你需要对定义了你要加载的类型的祖先类型的所有程序集都调用Assembly.ReflectionOnlyLoad。

举个例子,假设你在A.dll程序集中定义了以下类:

public class MyBase
{
   public void Foo() { }
}

并且在程序集B.dll中定义了以下类。

public class MySubclass : MyBase
{
}
当您在B.dll程序集上调用Assembly.GetTypes方法时,CLR将尝试加载类型MySubclass及其所有成员。由于方法Foo在A.dll程序集中的MyBase中定义(并且在B.dll元数据中不存在),如果A.dll程序集未加载,CLR将引发类型加载异常。

3
使用ReflectionOnlyLoad()加载的程序集中无法执行任何方法,否则会抛出InvalidOperationException异常。因此,这是使用反射确定程序集内容的安全方式。

1
另一个重要的区别是,Assembly.Load会将程序集添加到AppDomain中,而Assembly.ReflectionOnlyLoad不会将程序集添加到AppDomain中。
代码详细说明如下。
public void AssemblyLoadTest(string assemblyToLoad)
{
    var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    Assembly.ReflectionOnlyLoad(assemblyToLoad);
    var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    //Shows that assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
    Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4

    Assembly.Load(assemblyToLoad);
    var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5

    //Shows that assembly is loaded in to AppDomain with Assembly.Load
    Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}

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