2008-10-24 5 views
9

Je dois créer à des instances d'exécution d'une classe qui utilise des génériques, comme class<T>, sans savoir au préalable le type T ils auront, je voudrais faire quelque chose comme ça:Est-il impossible d'utiliser Generics dynamiquement?

public Dictionary<Type, object> GenerateLists(List<Type> types) 
{ 
    Dictionary<Type, object> lists = new Dictionary<Type, object>(); 

    foreach (Type type in types) 
    { 
     lists.Add(type, new List<type>()); /* this new List<type>() doesn't work */ 
    } 

    return lists; 
} 

... mais je ne peut pas. Je pense qu'il n'est pas possible d'écrire en C# dans les parenthèses génériques une variable de type. Y a-t-il un autre moyen de le faire?

+0

Pouvez-vous donner une raison pour laquelle vous souhaitez créer un objet générique de type sécurité lors de l'exécution? –

+0

Je l'ai fait plusieurs fois, en particulier lors du portage des tampons de protocole. –

+0

Je fais un adaptateur pour un cadre de persistance ici dans mon travail, et les classes ont besoin de cette information pour effectuer leur travail. –

Répondre

17

Vous ne pouvez pas le faire comme ça - le point de génériques est la plupart du temps compilation type sécurité - mais vous pouvez le faire avec la réflexion:

public Dictionary<Type, object> GenerateLists(List<Type> types) 
{ 
    Dictionary<Type, object> lists = new Dictionary<Type, object>(); 

    foreach (Type type in types) 
    { 
     Type genericList = typeof(List<>).MakeGenericType(type); 
     lists.Add(type, Activator.CreateInstance(genericList)); 
    } 

    return lists; 
} 
+0

merci encore Jon. Est-ce que CreateInstance nécessite un constructeur vide? Je ne l'ai pas, en fait j'ai besoin d'entrer un paramètre dedans. –

+0

Cela nécessite un constructeur. Si vous ne souhaitez pas utiliser un constructeur, vous pouvez utiliser FormatterServices.GetUninitializedObject() dans l'assembly System.Runtime.Serialization. –

+1

@Victor: Il existe des surcharges d'Activator.CreateInstance qui prennent des paramètres, ou vous pouvez utiliser Type.GetConstructor, puis l'appeler. Fondamentalement, il existe de nombreuses façons de passer d'un type à une instance d'un type - choisissez-en un :) –

4

En fonction de la fréquence que vous êtes appeler cette méthode puis en utilisant Activator.CreateInstance peut être lent. Une autre option est de faire quelque chose comme ceci:

Dictionnaire privé> délégués = nouveau Dictionnaire>(); Lors de la première occurrence, un délégué est créé dans la méthode générique qui crée la liste, puis le place dans un dictionnaire. À chaque frappe suivante, vous appellerez simplement le délégué pour ce type.

Espérons que cela aide!

+0

Merci jonni, j'appelle cette méthode juste une fois, sinon garder un délégué serait une bonne option. –