¿Cómo creo una clase genérica a partir de una cadena en C #?

Tengo una clase genérica como esa:

public class Repository {...} 

Y necesito instanciarlo con una cadena … Ejemplo:

 string _sample = "TypeRepository"; var _rep = new Repository(); 

¿Cómo puedo hacer eso? ¿Es eso posible?

¡Gracias!

Aquí está mi 2 centavos:

 Type genericType = typeof(Repository<>); Type[] typeArgs = { Type.GetType("TypeRepository") }; Type repositoryType = genericType.MakeGenericType(typeArgs); object repository = Activator.CreateInstance(repositoryType); 

Respondiendo la pregunta en comentario.

 MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething"); MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something)); closedMethod.Invoke(repository, new[] { "Query String" }); 

Primero obtenga el objeto Type usando Type.GetType(stringContainingTheGenericTypeArgument)

Luego use typeof(Repository<>).MakeGenericType(theTypeObject) para obtener un tipo genérico.

Y finalmente usa Activator.CreateInstance

Este es un trabajo para la palabra clave dynamic viene en C # 4.0.

Aquí hay algunos buenos hacks que te darán una instancia de tu objeto, pero no importa cuál sea la versión actual de C #, solo sabrá que tiene un object , y no puede hacer mucho con un objeto en sí mismo porque el C # actual no lo hace soporte de enlace tardío. Necesita poder, al menos, convertirlo en un tipo conocido para hacer algo con él. En última instancia, debe saber el tipo que necesita en el momento de la comstackción o no tiene suerte.

Ahora, si puede restringir su clase de repository a los tipos que implementan alguna interfaz conocida, estará en una mejor forma.

Si entiendo tu pregunta correctamente … ¿Qué estás tratando de hacer es tomar tu tipo (Repositorio ) y construir una implementación específica y genérica de eso en tiempo de ejecución?

Si es así, eche un vistazo a MakeGenericType . Puede usar typeof (Repository) y System.Type del objeto que desea para T y construirlo de esta manera. Una vez que tenga el tipo, Activator.CreateInstance funcionará para usted.

Suponiendo que su cadena tenga el nombre de un tipo, puede escribir

 object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample))); 

Sin embargo, _rep será un objeto sin tipo, y no tendrá forma de hacer nada con él. Como no sabe de qué tipo es la clase genérica en tiempo de comstackción, no hay ningún tipo en el que la genere. (A menos que Repository herede una clase no genérica o implemente una interfaz no genérica)

Podrías resolver eso haciendo una clase base no genérica para Repository y lanzándole el objeto.

Sin embargo, dependiendo de su situación, es probable que desee hacer que Repository una clase no genérica.

Si el Repository es una clase que contiene otras clases, probablemente sea mejor hacerlo no genérico. Puede hacer que su constructor tome un objeto Type y luego llamar a Type.IsInstanceOfType en cada objeto que agregue para asegurarse de que sea del tipo correcto.

Si Repository es una colección categorizada de cosas, probablemente sea mejor hacerlo no genérico, y hacer que su constructor tome una string category .

Si desea un asesoramiento más específico, publique más detalles sobre su situación.

 Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String")); object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName); 

Esto crearía una instancia de Repository . Puede reemplazar “System.String” con el tipo que desee.

Los generics funcionan en tipos, no en instancias. Puedes leer más aquí .

Parece que solo necesitas agregar un constructor a tu clase que tome el tipo deseado e initailice el valor:

 public class Foo { private T = default(T); public Foo(T initValue) { _val = T; } } 

Esto es “algo así” como posible. Algo así como que puedes hacerlo, pero es un poco complicado.

Tienes 3 opciones:

Si conoce sus clases por adelantado, use una statement de cambio. Básicamente así:

 switch(str){ case "TypeRepository": return new Repository; } 

Como una forma más avanzada de lo anterior, puede usar un diccionario en lugar de una tabla hash.

 var factory = new Dictionary>(); factory.Add( "TypeRepository", () => new Repository() ); var theObject = factory["TypeRepository"]() as Repository; 

Para obtener la mayor flexibilidad, puede usar el reflection para hacer coincidir cadenas con clases en tiempo de ejecución. Tenga en cuenta que la reflexión es bastante lenta, por lo que si está haciendo esto con cualquier tipo de regularidad, quiere evitarlo. Como ejemplo, Aquí hay uno que usa el método de Frans Bouma . Simplemente cambie List<> a Repository<> en su código:

 public static object MakeList( string typeStr ) { var nameSpace = "MyTestApplication" + "."; var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED var listType = typeof(List<>).MakeGenericType(objType); return Activator.CreateInstance(listType); } var listOfThings = MakeList("MyCoolObject") as List; 

Nota: No hay forma de evitar el hecho de que todos estos mecanismos devuelven un object , que luego debe convertir al tipo correcto, en lugar de devolver simplemente valores fuertemente tipados.

Esto es inevitable, porque no conoce el tipo de la lista hasta el tiempo de ejecución, y C # se basa en conocer cosas en tiempo de comstackción (esto es lo que las personas quieren decir cuando dicen “lenguaje de progtwigción tipado estáticamente”). Será menos doloroso en C # 4, donde podrá volver dynamic , lo que le ahorrará el lanzamiento.

La “T” en una clase genérica representa un tipo, no una instancia de un tipo. Entonces, si quieres que tu repository tenga objetos de cadena, utiliza

 var _rep = new Repository();