2008-11-17 8 views
15

Tengo un conjunto de clases, cada una es una strategy diferente para hacer el mismo trabajo.¿Crees un objeto sabiendo solo el nombre de la clase?

namespace BigCorp.SuperApp 
{ 
    public class BaseClass { } 
    public class ClassA : BaseClass { } 
    public class ClassB : BaseClass { } 
} 

La elección de qué estrategia usar es configurable. Quiero configurar solo el nombre de clase 'ClassB' en lugar del nombre de tipo completo 'BigCorp.SuperApp.ClassB' en el archivo app.config.

<appConfig> 
    <SuperAppConfig> 
     <Handler name="ClassB" /> 
    </SuperAppConfig> 
</appConfig> 

Sin embargo, las llamadas de reflexión fallan debido a que esperan que el nombre de tipo completo, sobre todo

Type t = Type.GetType("ClassB"); // results in t == null 
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails 

¿Cómo puedo conseguir que esto funcione mientras se configura sólo el nombre de la clase? Concatenar el espacio de nombre para el nombre de clase para el nombre de tipo completo? ¿Hay alguna otra llamada de reflexión que funcione?

Si cree que esto es inútil y debería esperar que la configuración contenga el nombre completo, ¡estoy abierto a esa solución! Solo proporcione la razón para convencerme.

(no voy a carga un tipo de fuera de este montaje/espacio de nombres)

+0

¡Podría usar un contenedor IoC, tratar nombres largos y obtener la creación de objetos para mí! –

Respuesta

6

Ya que sabes todas las clases van a venir desde el mismo espacio de nombres, configure una vez y el uso que:

<appConfig> 
    <SuperAppConfig handlerNamespace="BigCorp.SuperApp"> 
     <Handler class="ClassB" /> 
    </SuperAppConfig> 
</appConfig> 

Editar: he cambiado nombre a clase para indicar mejor el significado de ese atributo.

+0

Agradezco las respuestas, el código y la discusión sobre la carga del conjunto. Pero me gusta la respuesta de Bryan para centrarse en la configuración (ya que no puedo alejarme del nombre completo). –

18

utilizar el nombre de ensamblado-cualificado, o controlar la Asamblea y el uso Assembly.GetType(name). En este caso, ya que desea que los tipos en el archivo de configuración, montaje cualificado es una forma válida para ir - pero ya que usted sabe todos sus tipos están en la misma asamblea:

reglas
Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly! 
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate) 
object obj = Activator.CreateInstance(type); 

El estática Type.GetType(string) ha de sondeo que a menudo causa confusión ... mira el ensamblado de llamada y algunos ensambles de sistema, pero no todos los ensamblados cargados.

+0

Tengo una referencia de servicio que deseo llamar usando esto, pero no aparecerá en la lista de tipos del ensamblaje (hecho desde la clase). Aunque puedo crear un objeto de la referencia llamando al código duro del constructor. – MrFox

5
(I will not be loading a type from outside this assembly/namespace)

debido a la línea anterior, es seguro asumir que usted sabe lo que es el espacio de nombres. ¿No podría hacer algo como:

Type t = Type.GetType("Namespace." + className); 
BaseClass c = Activator.CreateInstance(t) as BaseClass; 

Si tiene previsto posiblemente ser capaz de añadir clases estrategia adicional para ser cargados en el futuro, tal vez a través de un montaje adicional, que tendría que calificar totalmente el nombre de la clase. Esto se recomienda de todos modos, ya que podría proporcionar ampliabilidad mejorada para su aplicación.

+0

Eso en realidad depende de dónde se encuentre ese código (y cómo se interpreta "desde afuera", es decir, ¿es esa clase? ¿O quien llama?). Sin un nombre calificado para el ensamblaje, Type.GetType (cadena) solo * mirará el ensamblaje actual y algunos ensambles del sistema. No encontrará tipos en dlls con referencias aleatorias. –

2

Voy con el nombre de tipo completo en la configuración de la aplicación.A continuación se muestra un ejemplo un poco más completa, pero todavía trivial

<SuperAppConfig> 
    <ObjectConfig provider="BigCorp.SuperApp.ClassA"> 
     <add name="one" /> 
     <add name="two" /> 
    </ObjectConfig> 
</SuperAppConfig> 

Y la clase de fábrica que crea en realidad este

private static Assembly a = typeof(IFactoryObject).Assembly; 
public static IFactoryObject CreateObject(String providerName) 
{ 
    Type t = a.GetType(providerName) 
    IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject; 
    return o; 
} 
1
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails 

también podría resultar del hecho, que CreateInstance no devuelve una instancia de BaseClass, en lugar de una instancia de BaseClass envuelto en un ObjectHandle.

Inyecte en su BaseClass después de utilizar el método UnWrap.

Cuestiones relacionadas