2010-07-28 21 views
17

Tengo un dll que contiene varias clases que todas heredan de una clase CommandBase. Estoy tratando de obtener instancias de todas estas clases (CommandA, CommandB, CommandC, etc ...) usando la reflexión en C# para poder llamar a un método específico en cada una de ellas. Esto es lo que tengo hasta ahora:Uso de la reflexión para obtener todas las clases de cierto tipo base en dll

//get assemblies in directory. 
string folder = Path.Combine(HttpContext.Current.Server.MapPath("~/"), "bin"); 
var files = Directory.GetFiles(folder, "*.dll"); 
//load each assembly. 
foreach (string file in files) 
{ 
    var assembly = Assembly.LoadFile(file); 
    if (assembly.FullName == "MyCommandProject") 
    { 
    foreach (var type in assembly.GetTypes()) 
    { 
     if (!type.IsClass || type.IsNotPublic) continue; 
     if(type is CommandBase) 
     { 
     var command = Activator.CreateInstance(type) as CommandBase; 
     } 
    } 
    } 
} 

Tengo 2 problemas. El primer problema es que la línea "if (type es CommandBase") da la siguiente advertencia:

La expresión dada nunca es del tipo provisto CommandBase.

El segundo problema es que no puedo entender cómo obtener una instancia del objeto real (CommandA, CommandB, etc ...), simplemente convertirlo a CommandBase no es suficiente.

+0

¿Su última línea no crea correctamente la instancia? 'Con Activator.CreateInstance()', debe tener una instancia de CommandA, CommandB ... clase (dependiendo de 'tipo'), ¿no? –

+0

Activation.CreateInstance() devuelve type object. – Justin

+0

Sí, pero devuelve un objeto del tipo que proporcionó. Puede almacenarlo en var de "objeto" o var de "CommandBase", seguirá siendo una instancia de CommandA, CommandB, etc. Puedes lanzarlo más tarde a su tipo "real". No tengo un Visual Studio para verificar pero no veo cuál es el problema. –

Respuesta

29

Este es el método que uso para cargar basado en una interfaz.

private static List<T> GetInstances<T>() 
{ 
     return (from t in Assembly.GetExecutingAssembly().GetTypes() 
       where t.GetInterfaces().Contains(typeof (T)) && t.GetConstructor(Type.EmptyTypes) != null 
       select (T) Activator.CreateInstance(t)).ToList(); 
} 

Y aquí está la misma función que se basa en la clase base.

private static IList<T> GetInstances<T>() 
{ 
     return (from t in Assembly.GetExecutingAssembly().GetTypes() 
         where t.BaseType == (typeof(T)) && t.GetConstructor(Type.EmptyTypes) != null 
         select (T)Activator.CreateInstance(t)).ToList(); 
} 

Por supuesto, tendría que modificarse ligeramente para apuntar a la referencia que está cargando.

+0

Gracias, pero por alguna razón solo devuelve la clase CommandBase, no las clases que heredan de ella. Además, si lo llamo "GetInstances ()", entonces me da una lista de objetos CommandBase, no los objetos que necesito - CommandA, CommandB, etc. Parece que necesito usar interfaces para que esto funcione . – Justin

+0

Agregó una segunda función para que la use en su clase CommandBase. Debería recuperar una lista de instancias de clases heredadas de CommandBase. Funciona cuando lo tiro en una prueba de fragmento simple. –

+0

Terminé cambiando a usar interfaces y usé su primer ejemplo de código, ¡gracias! – Justin

2

Eso es porque su variable type es un Type, no un CommandBase.

¿Quieres

if(type == typeof(CommandBase)) 

(Gracias Greg para la corrección)

+1

¿No sería 'if (type == typeof (CommandBase))'? – Greg

+1

Esto no funcionaría para las clases derivadas. –

+1

Terminó siendo "==" en lugar de "es", pero sí que funcionó, gracias. ¿Algún consejo sobre mi segundo número? – Justin

7

Cambio type is CommandBase a typeof(CommandBase).IsAssignableFrom(type)

+0

+1 Lo hizo bien –

+0

+1 No vi su resultado cuando estaba escribiendo, sin embargo, este msdn dice "Si IsSubclassOf es el inverso de IsAssignableFrom. Es decir, si t1.IsSubclassOf (t2) es verdadero, entonces t2. IsAssignableFrom (t1) también es verdadero ". entonces ambos tenemos la razón, estaba apuntando hacia las respuestas de es y == respuestas. –

6

Debe cambiar

if(type is CommandBase) 

a

if(type.IsSubclassOf(typeof(CommandBase))) 

Si IsSubclassOf es el inverso de IsAssignableFrom. Es decir, si t1.IsSubclassOf (t2) es verdadero, entonces t2.IsAssignableFrom (t1) también es verdadero.

+0

Es decir, a excepción de mi respuesta, que fue correcta desde el principio. :), pero te doy un +1 por estar en lo correcto y porque nunca me di cuenta del método IsSubclassOf, ya que solo uso IsAssignableFrom. –

Cuestiones relacionadas