2008-11-20 2 views
42

Я пытаюсь понять различия между Assembly.Load и Assembly.ReflectionOnlyLoad.C# Assembly.Load vs 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

ответ

23

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

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

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

8

Я считаю, что ваше общее понимание различий между 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 не была загружена.

6

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

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

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

1

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

Смежные вопросы