С# 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 делает отражение и "смотрит на" библиотеку... но это какой-то экземпляр принципа неопределенности Гейзенберга, при котором просмотр библиотеки и объектов в ней на самом деле пытается создать экземпляр они каким-то образом?
Спасибо,
Макс
Ответы
Ответ 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
. Таким образом, это безопасный способ определения содержимого сборки с использованием отражения.