2010-11-04 12 views
33

Digamos que tengo las siguientes clasesLlamar a un método genérico con un tipo dinámico

public class Animal { .... } 

public class Duck : Animal { ... } 

public class Cow : Animal { ... } 

public class Creator 
{ 
    public List<T> CreateAnimals<T>(int numAnimals) 
    { 
     Type type = typeof(T); 
     List<T> returnList = new List<T>(); 
     //Use reflection to populate list and return 
    } 
} 

Ahora en algún código más adelante quiero leer en qué animal para crear.

Creator creator = new Creator(); 
string animalType = //read from a file what animal (duck, cow) to create 
Type type = Type.GetType(animalType); 
List<animalType> animals = creator.CreateAnimals<type>(5); 

Ahora el problema es que la última línea no es válida. ¿Hay alguna manera elegante de hacer esto, entonces?

+2

Los genéricos no son realmente el camino a seguir aquí, solo debe crear una Lista y usar el Activador para crear las clases derivadas. – Doggett

Respuesta

18

No realmente. Necesitas usar la reflexión, básicamente. Los genéricos apuntan realmente a estática mecanografiando en lugar de tipos conocidos solo en tiempo de ejecución.

Para usar la reflexión, usaría Type.GetMethod para obtener la definición del método, luego llame al MethodInfo.MakeGenericMethod(type), luego instálelo como cualquier otro método.

46

No sé acerca elegante, pero la manera de hacerlo es:

typeof(Creator) 
    .GetMethod("CreateAnimals") 
    .MakeGenericMethod(type) 
    .Invoke(creator, new object[] { 5 }); 
+2

Aunque no podrá convertirlo como 'List ' o 'List ' etc. a menos que ya conozca el tipo en tiempo de compilación, que no es así. Lo mejor que puedes hacer es lanzar a 'IList'. – LukeH

+0

@LukeH, correcto, buen punto. –

+0

esto es tan feo, pero es la respuesta correcta – tofutim

1

Las claves de este son MakeGenericType() y MakeGenericMethod(). Una vez que te has vuelto dinámico con los tipos, no puedes volver al tipado estático. Lo que PUEDE hacer es crear la lista dinámicamente, usando Activator.CreateInstance(typeof(List<>).MakeGenericType(type)) y luego llamar dinámicamente al método genérico utilizando métodos reflectantes similares.

3

Prueba esto:

public List<T> CreateAnimals<T>(int numAnimals) where T : Animal 
{ 
    Type type = typeof(T); 
    List<T> returnList = new List<T>(); 
    //Use reflection to populate list and return 
} 

Debe asegurarse de que los tipos permitidos para CreateAnimals heredan de Animal. Luego de esperar, no va a tener un problema con List<animalType> animals = creator.CreateAnimals<type>(5);

+0

Eso realmente no ayuda si el OP quiere leer en qué tipo de animal crear a partir de una cadena. –

0
List<animalType> animals = 
creator.CreateAnimals<type>(5); 

En la línea anterior de su ejemplo, animalType y type se ejecute variables de tiempo, no tipos, así que esto es de sentido supuesto. Una versión genérica sólo tiene sentido, si conoce los tipos en tiempo de compilación, por ejemplo .:

List<Animal> animals = 
    creator.CreateAnimals<Cow>(5); 

donde tendría a la restricción tipos consecuencia. Si los tipos no se conocen, debe confiar completamente en la reflexión ...

Cuestiones relacionadas