【问题标题】:C# Assembly.Load vs Assembly.ReflectionOnlyLoadC# Assembly.Load 与 Assembly.ReflectionOnlyLoad
【发布时间】:2008-11-20 16:08:39
【问题描述】:

我试图了解 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 属性了解更多信息 信息。

我假设上面的代码只是在进行反射并“查看”库......但这是否是海森堡不确定性原则的某种实例,即查看库和其中的对象实际上是在尝试实例化他们以某种方式?

谢谢, 最大

【问题讨论】:

    标签: c# reflection assembly.load assembly.reflectiononly


    【解决方案1】:

    根据 Jon 的回复,了解 LoaderExceptions 中的内容会很有帮助。代替这些信息,我想我可以冒险猜测。来自MSDN

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

        我相信您对 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 是在 MyBase 中的程序集 A.dll 中定义的(并且不存在于 B.dll 的元数据中),如果程序集 A.dll 尚未加载,CLR 将抛出类型加载异常。

        【讨论】:

          【解决方案4】:

          没有方法可以从程序集中执行,加载ReflectionOnlyLoad(),你会得到InvalidOperationException。所以这是使用反射确定程序集内容的安全方法。

          【讨论】:

            【解决方案5】:

            两者之间的另一个大区别是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
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-09-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-03-22
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多