2010-11-04 3 views
33

permet de dire que j'ai les classes suivantesappelle une méthode générique avec un type dynamique

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 
    } 
} 

maintenant dans un code plus tard, je veux lire dans quel animal pour créer.

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); 

Maintenant, le problème est que la dernière ligne n'est pas valide. Y a-t-il une manière élégante de faire ceci alors?

+2

Les génériques ne sont pas vraiment la voie à suivre ici, vous devriez simplement créer une liste à la place et utiliser Activator pour créer les classes dérivées. – Doggett

Répondre

18

Pas vraiment. Vous devez utiliser la réflexion, fondamentalement. Les génériques visent vraiment statique en tapant plutôt que des types seulement connus au moment de l'exécution.

Pour utiliser la réflexion, vous devez utiliser Type.GetMethod pour obtenir la définition de la méthode, puis appeler le MethodInfo.MakeGenericMethod(type), puis l'appeler comme toute autre méthode.

46

Je ne sais pas élégant, mais la façon de le faire est:

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

Bien que vous ne puissiez pas le transformer en 'Liste ' ou 'Liste ' etc, sauf si vous connaissez déjà le type lors de la compilation, ce qui n'est pas le cas. Le mieux que vous puissiez faire est de lancer 'IList'. – LukeH

+0

@LukeH, à droite, bon point. –

+0

c'est tellement moche, mais c'est la bonne réponse – tofutim

1

Les clés de ce sont MakeGenericType() et MakeGenericMethod(). Une fois que vous êtes devenu dynamique avec les types, vous ne pouvez pas vraiment revenir à la saisie statique. Ce que vous pouvez faire est de créer la liste dynamiquement, en utilisant Activator.CreateInstance(typeof(List<>).MakeGenericType(type)), puis en appelant dynamiquement la méthode générique en utilisant des méthodes de réflexion similaires.

3

Essayez ceci:

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 
} 

Il faut veiller à ce que les types autorisés pour CreateAnimals hériteront d'animaux. Ensuite, espérons-le, il ne sera pas un problème avec List<animalType> animals = creator.CreateAnimals<type>(5);

+0

Cela n'aide pas vraiment si l'OP veut lire dans quel type d'animal créer à partir d'une chaîne. –

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

Dans la ligne ci-dessus de votre exemple, animalType et type sont gérées variables de temps, pas les types, donc c'est évidemment absurde. Une version générique n'a de sens, si vous connaissez les types au moment de la compilation, .: par exemple

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

où vous auriez à la contrainte des types en conséquence. Si les types ne sont pas connus, vous devez compter entièrement sur la réflexion ...

Questions connexes