Сборку C#.Загрузка vs сборка.ReflectionOnlyLoad

Я пытаюсь понять различия между сборкой.Загрузка и сборка.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);
   }
}

этот код отлично работает для меня, но я занимался некоторыми исследованиями других, возможно, лучших альтернатив и наткнулся на сборку.ReflectionOnlyLoad() метод.

я предположил, что, поскольку я не загружаю или не выполняю объекты, по сути, просто запрашивают их определения, которые я мог бы использовать ReflectionOnlyLoad для небольшого повышения производительности...

но оказывается, что когда я меняю сборку.Загрузка в сборку.ReflectionOnlyLoad я получаю следующую ошибку при вызове сборки.GetTypes():

System.Reflection.ReflectionTypeLoadException:

не удается загрузить один или более тип запроса. Получить Свойства LoaderExceptions для получения дополнительной информация.

я предположил, что выше код просто делал отражение и" смотрел " на библиотеку... но является ли это своего рода примером принципа неопределенности Гейзенберга, когда, глядя на библиотеку и объекты в ней, на самом деле пытается их каким-то образом создать?

спасибо, Макс!--3-->

5 ответов


согласно ответу Джона, было бы полезно знать, что в LoaderExceptions. Вместо этой информации, я думаю, что могу рискнуть предположить. От MSDN:

Если сборка имеет зависимости, то Метод ReflectionOnlyLoad не загружать их. Если вам нужно осмотреть вы должны сами их загрузить.

вам нужно прикрепить обработчик к AppDomain.ReflectionOnlyAssemblyResolve чтобы помочь CLR загрузить любые зависимости загружаемой сборки. Вы сделали это?


Я считаю, что ваше общее понимание различий между нагрузкой и ReflectionOnlyLoad правильно. Проблема здесь (я думаю) заключается в том, что даже для простой загрузки типа CLR необходимо прочитать метаданные из сборки, сам тип определен в также загрузите метаданные из каждой сборки, предки типа определены в. Итак, вам нужно вызвать сборку.ReflectionOnlyLoad для всех сборок, определяющих типы, которые являются предками типов, которые вы погрузка.

чтобы привести пример, предположим, что в сборке определен следующий класс A.dll - ...

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

и следующий класс, определенный в сборке B.dll - ...

public class MySubclass : MyBase
{
}

при вызове сборки.GetTypes на сборке B.dll, среда CLR попытается загрузить тип MySubclass и все его члены. Поскольку метод Foo определен в mybase в сборке A.dll (и не существует нигде в метаданных B.dll), среда CLR выдаст исключения типа load, если сборка A.dll не был загружен.


методы ReflectionOnly-единственный способ загрузить определенную сборку на диск для изучения без использования обычных правил Load/LoadFrom. Например, можно загрузить сборку на основе диска с тем же идентификатором, что и в GAC. Если вы пробовали это с LoadFrom или LoadFile, сборка GAC всегда загружается.

кроме того, вы не можете вызывать GetCustomAttributes (...) на экземпляре возвращаемой сборки, так как это попытается создать экземпляр атрибутов на агрегат, которые ReflectionOnly. Для этого необходимо использовать статические методы класса CustomAttributeData.

никакие типы в сборке, загруженной через ReflectionOnly, не могут быть созданы.


ни один метод не может быть выполнен из сборки, загруженной с ReflectionOnlyLoad(), вы InvalidOperationException. Таким образом, это безопасный способ определения содержимого сборки с помощью отражения.


еще одна большая разница между двумя 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
}