我正在尝试理解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属性更多 信息。
我认为上面的代码只是做反射和“查看”库...但这是海森堡不确定性原理的某种实例,其中查看库及其中的对象实际上是试图实例化他们以某种方式?
谢谢, 最大
答案 0 :(得分:26)
根据Jon的回复,了解LoaderExceptions
中的内容会很有帮助。代替这些信息,我想我可以冒险猜测。来自MSDN:
如果程序集有依赖关系,那么 ReflectionOnlyLoad方法没有 加载他们。如果你需要检查 他们,你必须自己加载它们。
您需要将处理程序附加到AppDomain.ReflectionOnlyAssemblyResolve
以帮助CLR加载您正在加载的程序集的任何依赖项。你做过这个吗?
答案 1 :(得分:10)
我相信您对Load和ReflectionOnlyLoad之间差异的一般理解是正确的。这里的问题(我认为)即使只是简单地加载一个类型,CLR也需要从程序集中读取元数据,类型本身在中定义,并从每个程序集加载元数据,类型的祖先在< / em>的。因此,您需要在所有程序集上调用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将抛出类型加载异常。
答案 2 :(得分:8)
ReflectionOnly方法是您可以在磁盘上加载特定程序集以进行检查的唯一方法,而无需通过通常的Load / LoadFrom规则。例如,您可以加载基于磁盘的程序集,其标识与GAC中的标识具有相同的标识。如果您使用LoadFrom或LoadFile尝试此操作,则GAC程序集始终已加载。
此外,您可能不会在返回程序集实例上调用GetCustomAttributes(...),因为这将尝试实例化程序集上的属性,即ReflectionOnly。您必须使用CustomAttributeData类的静态方法。
可以实例化通过ReflectionOnly加载的程序集中的任何类型。
答案 3 :(得分:3)
无法从程序集执行任何方法,加载ReflectionOnlyLoad()
,您将获得InvalidOperationException
。因此,这是使用反射确定装配内容的安全方法。
答案 4 :(得分:0)
两者之间的另一个重大差异是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
}