C # Assembly.Load vs Assembly.ReflectionOnlyLoad - PullRequest
45 голосов
/ 20 ноября 2008

Я пытаюсь понять разницу между 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 для более информация.

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

Спасибо, Max

Ответы [ 5 ]

26 голосов
/ 20 ноября 2008

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

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

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

10 голосов
/ 20 ноября 2008

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

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

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

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

public class MySubclass : MyBase
{
}

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

8 голосов
/ 20 ноября 2008

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

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

Не допускается создание экземпляров типов в сборке, загруженной через ReflectionOnly.

3 голосов
/ 19 марта 2009

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

0 голосов
/ 13 марта 2018

Еще одно большое различие между ними состоит в том, что 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
}
...