Подтвердить что ты не робот

С# Assembly.Load vs. Assembly.ReflectionOnlyLoad

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

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

Спасибо, Макс

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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