C# Assembly.Load 与 Assembly.ReflectionOnlyLoad

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/305835/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:28:00  来源:igfitidea点击:

C# Assembly.Load vs Assembly.ReflectionOnlyLoad

c#reflectionassembly.loadassembly.reflectiononly

提问by Max Schilling

I'm trying to understand the differences between Assembly.Load and Assembly.ReflectionOnlyLoad.

我试图了解 Assembly.Load 和 Assembly.ReflectionOnlyLoad 之间的差异。

In the code below I am attempting to find all of the objects in a given assembly that inherit from a given interface:

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

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);
   }
}

This code works fine for me, but I was doing some research into other possibly better alternatives and came across Assembly.ReflectionOnlyLoad() method.

这段代码对我来说很好用,但我正在研究其他可能更好的替代方案,并遇到了 Assembly.ReflectionOnlyLoad() 方法。

I assumed that since I'm not loading or executing any of the objects, essentially just querying on their definitions that I could use ReflectionOnlyLoad for a slight performance increase...

我假设因为我没有加载或执行任何对象,基本上只是查询它们的定义,我可以使用 ReflectionOnlyLoad 来稍微提高性能......

But it turns out that when I change Assembly.Load to Assembly.ReflectionOnlyLoad I get the following error when it calls assembly.GetTypes():

但事实证明,当我将 Assembly.Load 更改为 Assembly.ReflectionOnlyLoad 时,在调用 assembly.GetTypes() 时出现以下错误:

System.Reflection.ReflectionTypeLoadException:

Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

System.Reflection.ReflectionTypeLoadException:

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

I assumed that the above code was JUST doing reflection and "looking at" the library... but is this some sort of instance of the Heisenberg Uncertainty Principle whereby looking at the library and the objects in it is actually attempting to instantiate them in some way?

我认为上面的代码只是在做反射和“查看”库......但这是海森堡不确定性原理的某种实例,即查看库和其中的对象实际上是试图在某些情况下实例化它们道路?

Thanks, Max

谢谢,马克斯

采纳答案by Kent Boogaart

As per Jon's reply, it would be helpful to know what's in LoaderExceptions. In lieu of this information, I think I can hazard a guess. From MSDN:

根据 Jon 的回复,了解LoaderExceptions. 代替这些信息,我想我可以冒险猜测一下。从MSDN

If the assembly has dependencies, the ReflectionOnlyLoad method does not load them. If you need to examine them, you must load them yourself.

如果程序集具有依赖项,则 ReflectionOnlyLoad 方法不会加载它们。如果您需要检查它们,您必须自己加载它们。

You need to attach a handler to AppDomain.ReflectionOnlyAssemblyResolveto help the CLR load any dependencies of the assembly you're loading. Have you done this?

您需要附加一个处理程序以AppDomain.ReflectionOnlyAssemblyResolve帮助 CLR 加载您正在加载的程序集的任何依赖项。你这样做了吗?

回答by C. Dragon 76

I believe your general understanding of the differences between Load and ReflectionOnlyLoad is correct. The problem here (I think) is that even to simply load a type, the CLR needs to read the metadata from the assembly the type itself is defined in as well load the metadata from every assembly the type's ancestors are defined in. So, you need to call Assembly.ReflectionOnlyLoad on all assemblies that define types that are ancestors of the types you're loading.

我相信您对 Load 和 ReflectionOnlyLoad 之间差异的一般理解是正确的。这里的问题(我认为)是,即使只是简单地加载一个类型,CLR 也需要从定义类型本身的程序集中读取元数据,并从定义类型的祖先的每个程序集中加载元数据。因此,您需要在所有定义类型的程序集上调用 Assembly.ReflectionOnlyLoad,这些类型是您正在加载的类型的祖先。

To give an example, suppose you have the following class defined in assembly A.dll.

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

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

and the following class defined in assembly B.dll.

以及程序集 B.dll 中定义的以下类。

public class MySubclass : MyBase
{
}

When you call Assembly.GetTypes on assembly B.dll, the CLR will try to load the type MySubclass and all of its members. Because the method Foo is defined in MyBase in assembly A.dll (and exists nowhere in the metadata of B.dll), the CLR will throw the type load exceptions if assembly A.dll has not been loaded.

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

回答by x0n

The ReflectionOnly methods are the only way you can load a specific Assembly on disk to examine without going via the usual Load/LoadFrom rules. For example, you can load a disk-based assembly with the same identity as one in the GAC. If you tried this with LoadFrom or LoadFile, the GAC assembly is ALWAYS loaded.

ReflectionOnly 方法是您可以在磁盘上加载特定程序集以进行检查而无需通过通常的 Load/LoadFrom 规则的唯一方法。例如,您可以加载与 GAC 中标识相同的基于磁盘的程序集。如果您尝试使用 LoadFrom 或 LoadFile 执行此操作,则始终加载 GAC 程序集。

Additionally, you may not call GetCustomAttributes(...) on the return Assembly instance since this will attempt to instantiate the Attributes on the assembly, which are ReflectionOnly. You must use CustomAttributeData class's static methods for this.

此外,您不能在返回的程序集实例上调用 GetCustomAttributes(...),因为这将尝试实例化程序集上的 Attributes,它们是 ReflectionOnly。为此,您必须使用 CustomAttributeData 类的静态方法。

No types in an assembly loaded via ReflectionOnly may be instantiated.

通过 ReflectionOnly 加载的程序集中的任何类型都不能被实例化。

回答by abatishchev

No method can be executed from assembly, loaded with ReflectionOnlyLoad(), you will get InvalidOperationException. So this is safe way to determine assembly content using reflection.

无法从程序集中执行任何方法,加载ReflectionOnlyLoad(),您将获得InvalidOperationException. 所以这是使用反射确定程序集内容的安全方法。

回答by Gerrie Pretorius

Another big difference between the two is Assembly.Loadadds the assembly into the AppDomainwhere as Assembly.ReflectionOnlyLoadwill not add the assembly in to the AppDomain

两者之间的另一个很大区别是Assembly.Load将程序集添加到AppDomainwhere asAssembly.ReflectionOnlyLoad不会将程序集添加到AppDomain

code to show in detail.

代码来详细展示。

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
}