Pase un sistema instanciado. Escriba como un parámetro de tipo para una clase genérica.

El título es algo oscuro. Lo que quiero saber es si esto es posible:

string typeName = ; Type myType = Type.GetType(typeName); MyGenericClass myGenericClass = new MyGenericClass(); 

Obviamente, MyGenericClass se describe como:

 public class MyGenericClass 

En este momento, el comstackdor se queja de que ‘El tipo o el espacio de nombres’ myType ‘no se pudo encontrar. “Tiene que haber una manera de hacer esto.

No puedes hacer esto sin reflexión. Sin embargo, puedes hacerlo con reflexión. Aquí hay un ejemplo completo:

 using System; using System.Reflection; public class Generic { public Generic() { Console.WriteLine("T={0}", typeof(T)); } } class Test { static void Main() { string typeName = "System.String"; Type typeArgument = Type.GetType(typeName); Type genericClass = typeof(Generic<>); // MakeGenericType is badly named Type constructedClass = genericClass.MakeGenericType(typeArgument); object created = Activator.CreateInstance(constructedClass); } } 

Nota: si su clase genérica acepta múltiples tipos, debe incluir las comas cuando omite los nombres de tipo, por ejemplo:

 Type genericClass = typeof(IReadOnlyDictionary<,>); Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2); 

Desafortunadamente no, no hay. Los argumentos generics deben poder resolverse en Tiempo de comstackción como 1) un tipo válido o 2) otro parámetro genérico. No hay forma de crear instancias genéricas basadas en valores de tiempo de ejecución sin el gran martillo del uso de la reflexión.

Mis requisitos eran ligeramente diferentes, pero espero ayudar a alguien. Necesitaba leer el tipo de una configuración y crear una instancia del tipo genérico de forma dinámica.

 namespace GenericTest { public class Item { } } namespace GenericTest { public class GenericClass { } } 

Finalmente, así es como lo llamas. Define el tipo con un backtick .

 var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest"); var a = Activator.CreateInstance(t); 

Algunos adicionales sobre cómo correr con el código de tijeras. Supongamos que tiene una clase similar a

 public class Encoder() { public void Markdown(IEnumerable contents) { do magic } public void Markdown(IEnumerable contents) { do magic2 } } 

Supongamos que en tiempo de ejecución tiene un FooContent

Si pudieras enlazar en tiempo de comstackción querrías

 var fooContents = new List(fooContent) new Encoder().Markdown(fooContents) 

Sin embargo, no puedes hacer esto en tiempo de ejecución. Para hacer esto en tiempo de ejecución, harías lo siguiente:

 var listType = typeof(List<>).MakeGenericType(myType); var dynamicList = Activator.CreateInstance(listType); ((IList)dynamicList).Add(fooContent); 

Para invocar dinámicamente el contenido de Markdown(IEnumerable contents)

 new Encoder().Markdown( (dynamic) dynamicList) 

Tenga en cuenta el uso de dynamic en la llamada al método. En tiempo de ejecución, dynamicList será List (además, también será IEnumerable ), ya que el uso uniforme de dynamic aún está enraizado en un lenguaje fuertemente tipado, el corrector de tiempo de ejecución seleccionará el método Markdown adecuado. Si no hay coincidencias de tipos exactos, buscará un método de parámetro de objeto y si ninguno coincide con una excepción de encuadernador de tiempo de ejecución se generará una alerta que no coincide con ningún método.

El obvio inconveniente de este enfoque es una gran pérdida de seguridad de tipo en tiempo de comstackción. Sin embargo, el código a lo largo de estas líneas le permitirá operar en un sentido muy dynamic que en el tiempo de ejecución aún está completamente tipeado como espera que sea.