2008-11-20 8 views
42

Estoy tratando de entender las diferencias entre Assembly.Load y Assembly.ReflectionOnlyLoad.C# Assembly.Load vs Assembly.ReflectionOnlyLoad

En el siguiente código que estoy tratando de encontrar todos los objetos de un montaje que se indica que heredan de una interfaz determinada:

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); 
    } 
} 

Este código funciona bien para mí, pero yo estaba haciendo algunas investigaciones en otra posiblemente mejores alternativas y se encontró con el método Assembly.ReflectionOnlyLoad().

Supuse que ya que no estoy de cargar o ejecutar cualquiera de los objetos, esencialmente sólo en la consulta de sus definiciones que podría utilizar ReflectionOnlyLoad para un aumento de rendimiento ligero ...

Pero resulta que cuando Assembly.Load cambiar a Assembly.ReflectionOnlyLoad me sale el siguiente error cuando se llama a assembly.GetTypes():

System.Reflection.ReflectionTypeLoadException: 

No se puede cargar uno o más de los tipos solicitados . Recupere la propiedad LoaderExceptions para obtener más información sobre .

que supone que el código anterior fue haciendo precisamente la reflexión y "mirar" la biblioteca ... pero esto es una especie de instancia del principio de incertidumbre de Heisenberg el que busca en la biblioteca y los objetos en ella es en realidad tratando de crear una instancia de alguna manera?

Gracias, Max

Respuesta

23

De acuerdo con la respuesta de Jon, sería útil saber qué hay en LoaderExceptions. En lugar de esta información, creo que puedo arriesgarme. De MSDN:

Si el conjunto tiene dependencias, el método ReflectionOnlyLoad no cargarlos. Si necesita examinarlos , debe cargarlos usted mismo.

Debe conectar un controlador a AppDomain.ReflectionOnlyAssemblyResolve para ayudar al CLR a cargar las dependencias del conjunto que está cargando. ¿Has hecho esto?

8

Creo que su comprensión general de las diferencias entre Load y ReflectionOnlyLoad es correcta. El problema aquí (creo) es que, incluso para simplemente cargar un tipo, el CLR necesita leer los metadatos del ensamblado, el tipo se define en y cargar los metadatos de cada ensamblaje los antecesores del tipo definidos en. Por lo tanto, debe llamar a Assembly.ReflectionOnlyLoad en todos los ensamblados que definan tipos que son ancestros de los tipos que está cargando.

Para dar un ejemplo, suponga que tiene la siguiente clase definida en el conjunto A.dll.

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

y la siguiente clase definida en el conjunto B.dll.

public class MySubclass : MyBase 
{ 
} 

Cuando llama a Assembly.GetTypes en el conjunto B.dll, el CLR intentará cargar el tipo MySubclass y todos sus miembros. Como el método Foo se define en MyBase en el ensamblado A.dll (y no existe en los metadatos de B.dll), el CLR emitirá las excepciones de carga de tipo si el ensamblado A.dll no se ha cargado.

6

Los métodos ReflectionOnly son la única forma de cargar un Assembly específico en el disco para examinar sin pasar por las reglas habituales Load/LoadFrom. Por ejemplo, puede cargar un ensamblaje basado en disco con la misma identidad que uno en el GAC. Si ha intentado esto con LoadFrom o LoadFile, el ensamblado de GAC SIEMPRE está cargado.

Además, no puede llamar a GetCustomAttributes (...) en la instancia de ensamblaje de devolución ya que esto intentará crear una instancia de los atributos en el ensamblaje, que son ReflectionOnly. Debe usar los métodos estáticos de la clase CustomAttributeData para esto.

No se pueden crear instancias de ningún tipo de un conjunto cargado a través de ReflectionOnly.

1

Ningún método se puede ejecutar desde el ensamblado, cargado con ReflectionOnlyLoad(), obtendrá InvalidOperationException. Entonces, esta es una forma segura de determinar el contenido del ensamblaje mediante la reflexión.