Pregunta

Estoy tratando de entender la reflexión, así que decidí agregar la capacidad de un complemento a un programa que estoy escribiendo.La única forma de entender un concepto es ensuciarse los dedos y escribir el código, así que seguí el camino de crear una biblioteca de interfaz simple que consta de las interfaces IPlugin e IHost, una biblioteca de implementación de complementos de clases que implementan IPlugin y una Proyecto de consola que crea una instancia de la clase de implementación IHost que realiza un trabajo simple con los objetos del complemento.

Usando la reflexión, quería iterar a través de los tipos contenidos dentro de la dll de implementación de mi complemento y crear instancias de tipos.Pude crear instancias de clases con éxito con este código, pero no pude transmitir el objeto creado a la interfaz.

Probé este código pero no pude convertir el objeto como esperaba.Recorrí el proceso con el depurador y se llamó al constructor adecuado.El objeto de observación rápida o me mostró que tenía los campos y propiedades que esperaba ver en la clase de implementación.

loop through assemblies
  loop through types in assembly
    // Filter out unwanted types
    if (!type.IsClass || type.IsNotPublic || type.IsAbstract )
      continue;
    // This successfully created the right object
    object o = Activator.CreateInstance(type);
    // This threw an Invalid Cast Exception or returned null for an "as" cast
    // even though the object implemented IPlugin      
    IPlugin i = (IPlugin) o;

Hice que el código funcionara con esto.

using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();

Aquí están mis preguntas:

  1. Activator.CreateInstance(Type t) devuelve un objeto, pero no pude convertir el objeto a una interfaz que el objeto implementó.¿Por qué?
  2. ¿Debería haber usado una sobrecarga diferente de CreateInstance()?
  3. ¿Cuáles son los consejos y trucos relacionados con la reflexión?
  4. ¿Hay alguna parte crucial de la reflexión que simplemente no entiendo?
¿Fue útil?

Solución

Solo estoy adivinando porque a partir de su código no es obvio dónde tiene la definición de la interfaz IPlugin, pero si no puede transmitir en su aplicación host, entonces probablemente tenga la interfaz IPlugin en su ensamblaje host y luego al mismo tiempo en su conjunto de complementos.Esto no funcionará.

Lo más fácil es hacer que esto funcione es tener la interfaz IPlugin marcada como pública en su ensamblado de host y luego tener su ensamblado de complemento. ensamblaje de la aplicación host de referencia, por lo que ambas asambleas tienen acceso a la misma interfaz.

Otros consejos

mmm...Si está utilizando Assembly.LoadFrom para cargar su ensamblaje, intente cambiarlo Assembly.LoadFile en su lugar.

Trabajó para mi

De aquí: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx

@lubos hasko

Lo has clavado en la nariz.Mi diseño original tenía tres ensamblajes diferentes y tanto la implementación del host como del complemento hacían referencia al ensamblaje de la interfaz del complemento.

Probé una solución separada con una implementación de host y un ensamblaje de interfaz y un ensamblaje de implementación de complemento.Dentro de esa solución, el código del primer bloque funcionó como se esperaba.

Me ha dado un poco más en qué pensar, porque no entiendo muy bien por qué dos ensamblajes que hacen referencia a un ensamblaje común no obtienen el mismo tipo del ensamblaje común.

¡Estaba tratando de resolver esto por mí mismo y logré encontrar la respuesta!

Tenía 3 proyectos diferentes de C#

  • A - Proyecto de interfaz de complemento
  • B - Proyecto host exe -> referencias A
  • C - Proyecto de implementación del complemento -> referencias A

También recibí el error de transmisión hasta que cambié el nombre del ensamblaje de mi proyecto de interfaz de complemento para que coincida con el espacio de nombres de lo que estaba intentando transmitir.

P.ej.

IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);

estaba fallando porque el ensamblado en el que se definió la interfaz IPluginModule se llamaba 'Común'. Sin embargo, el tipo al que estaba transmitiendo era 'Blah.Plugins.Common.IPluginModule'.

Cambié el nombre del ensamblaje para el proyecto de interfaz a 'Blah.Plugins.Common', lo que significa que la transmisión se realizó correctamente.

Ojalá esta explicación ayude a alguien.De vuelta al código...

¿Su tipo no es público? Si es así, llame a la sobrecarga que toma un valor booleano:

Activator.CreateInstance(type, true);

Además, en su primer ejemplo, vea si o es nulo y, si no, imprima o.GetType().Name para ver qué es realmente.

@pirateado

Intenté mantener el pseudocódigo simple.Los foreach ocupan mucho espacio y tirantes.Lo aclaré.

o.GetType().FullName devuelve Plugins.Multiply que es el objeto esperado.Plugins.Multiply implementa IPlugin.Recorrí el proceso en el depurador varias veces hasta que me di por vencido por la noche.No pude entender por qué no pude lanzarlo porque vi cómo el constructor disparaba hasta que me puse de mal humor por todo el desastre.Volví esta tarde y lo hice funcionar, pero todavía no entiendo por qué falló la conversión en el primer bloque de código.El segundo bloque de código funciona, pero no me parece bien.

El enlace a egghead anterior es la solución principal al problema: use Assembly.LoadFile() en lugar de .LoadFrom()

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top