2008-08-28 6 views
10

Estoy tratando de ajustar mi cabeza a la reflexión, así que decidí agregar capacidad de 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 fui por la ruta de crear una biblioteca de interfaz simple que constaba de las interfaces IPlugin e IHost, una biblioteca de implementación de complementos de clases que implementan IPlugin y un sencillo proyecto de consola que ejemplifica la clase de implementación IHost que hace un trabajo simple con los objetos del complemento.Cómo moldear adecuadamente los objetos creados a través de la reflexión

Al utilizar la reflexión, quise recorrer los tipos que figuran dentro de mi plugin implementation dll y crear instancias de tipos. Pude instanciar con éxito las clases con este código, pero no pude convertir el objeto creado a la interfaz.

He intentado este código pero no he podido lanzar el objeto o como esperaba. Pasé por el proceso con el depurador y se llamó al constructor adecuado. El objeto Quickwatching o me mostró que tenía los campos y las 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 funcione 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 (tipo T) devuelve un objeto, pero no pude convertir el objeto a una interfaz que implementa el objeto. ¿Por qué?
  2. ¿Debo haber estado usando 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 no estoy obteniendo?

Respuesta

4

Estoy adivinando aquí porque de su código no es obvio dónde tiene la definición de la interfaz IPlugin, pero si no puede convertir su aplicación host probablemente tenga interfaz IPlugin en su ensamblado de host y luego en al mismo tiempo en su ensamblaje de complemento. Esto no funcionará

Lo más fácil es hacer este trabajo es hacer que la interfaz IPlugin marcado como público en su conjunto del anfitrión y luego tener su montaje Plugin ensamblaje aplicación host referencia, por lo que ambos conjuntos tienen acceso a la misma interfaz de.

+2

Tal vez un poco exagerado para una aplicación simple, pero una alternativa es crear una biblioteca separada que solo contenga la interfaz y hacer referencia a ella de todo lo que necesite saber al respecto: o) – Andrew

+0

Sí, tiene razón. esa también es una solución válida. –

0

es tu tipo no pública, si es así, llame a la sobrecarga que lleva en un valor lógico:

Activator.CreateInstance(type, true); 

Además, en el primer ejemplo, ver si o es nulo y si no, imprimir o .GetType(). Nombre para ver lo que realmente es.

0

@Haacked

Traté de mantener la simplicidad del pseudocódigo. foreach ocupa mucho espacio y llaves. Lo aclaré

o.GetType(). FullName devuelve Plugins.Multiply, que es el objeto esperado. Plugins.Multiply implementa IPlugin. Pasé por el proceso en el depurador unas cuantas veces hasta que me rendí por la noche. No pude entender por qué no pude lanzarlo porque vi cómo el constructor disparaba hasta que me enojé por todo el desastre. Volví a hacerlo esta noche y lo hice funcionar, pero todavía no entiendo por qué falló el reparto en el primer bloque de código. El segundo bloque de código funciona, pero me parece desagradable.

1

@lubos hasko

Usted clavó en la nariz. Mi diseño original tenía tres ensamblajes diferentes con la implementación del host y del complemento que hacía referencia al ensamblaje de la interfaz del complemento.

Probé una solución separada con un ensamblado de implementación e interfaz de host y un ensamblado de implementación de complemento. Dentro de esa solución, el código en el 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 conjunto común no obtienen el mismo tipo del conjunto común.

1

¡Estaba tratando de solucionar esto y logré encontrar la respuesta!

que tenía 3 proyectos diferentes de C#

  • A - proyecto Plugin Interface
  • B - proyecto EXE Host -> hace referencia a un
  • C - Plugin Proyecto de ejecución -> hace referencia a un

Estaba obteniendo el error de conversión hasta que cambié el nombre del ensamblado para mi proyecto de interfaz de complementos para que coincida con el espacio de nombres de lo que estaba intentando convertir.

E.g.

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

estaba fallando debido a la asamblea que la interfaz IPluginModule se definió en la era llamado 'común', El -tipo- me echo a era 'Blah.Plugins.Common.IPluginModule' sin embargo.

Cambié el nombre del ensamblado para que el proyecto de interfaz fuera 'Blah.Plugins.Common' significaba que el reparto tenía éxito.

Afortunadamente esta explicación ayuda a alguien. Volver al código ...

0

El enlace a EGGHEAD anterior es la principal solución a la Assembly.LoadFile consumo problemático() en lugar de .LoadFrom()

Cuestiones relacionadas