119 votes

Génériques en C#, utiliser le type d'une variable comme paramètre

J'ai une méthode générique

bool DoesEntityExist<T>(Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

Comment utiliser la méthode de la manière suivante :

Type t = entity.GetType();
DoesEntityExist<t>(entityGuid, transaction);

Je continue à recevoir l'erreur de compilation suivante :

Le nom de type ou d'espace de nom 't' pourrait n'a pas été trouvé (il vous manque une directive using ou une référence d'assemblage)

DoesEntityExist<MyType>(entityGuid, transaction);

fonctionne parfaitement mais je ne veux pas utiliser une directive if pour appeler la méthode avec un nom de type distinct à chaque fois.

160voto

Jon Skeet Points 692016

L'intérêt des génériques est de donner temps de compilation la sécurité des types - ce qui signifie que les types doivent être connus au moment de la compilation.

Vous puede appeler des méthodes génériques dont les types ne sont connus qu'au moment de l'exécution, mais vous devez utiliser la réflexion :

// For non-public methods, you'll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
                             .MakeGenericMethod(new Type[] { t });
method.Invoke(this, new object[] { entityGuid, transaction });

Ick.

Pouvez-vous faire votre en appelant générique à la place, et passer votre paramètre de type comme argument de type, en poussant la décision un niveau plus haut dans la pile ?

Si vous pouviez nous donner plus d'informations sur ce que vous faites, cela nous aiderait. Parfois, il peut être nécessaire d'utiliser la réflexion comme ci-dessus, mais si vous choisissez le bon moment pour le faire, vous pouvez vous assurer que vous ne devez le faire qu'une seule fois, et laisser tout ce qui se trouve en dessous de ce point utiliser le paramètre de type de manière normale.

33voto

Joe Lloyd Points 196

Une façon de contourner ce problème est d'utiliser le casting implicite :

bool DoesEntityExist<T>(T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

en l'appelant comme ça :

DoesEntityExist(entity, entityGuid, transaction);

En allant un peu plus loin, vous pouvez en faire une méthode d'extension (elle devra être déclarée dans une classe statique) :

static bool DoesEntityExist<T>(this T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

en l'appelant ainsi :

entity.DoesEntityExist(entityGuid, transaction);

7voto

kosto Points 61

Je ne suis pas sûr d'avoir bien compris votre question, mais vous pouvez écrire votre code de cette façon :

bool DoesEntityExist<T>(T instance, ....)

Vous pouvez appeler la méthode de la manière suivante :

DoesEntityExist(myTypeInstance, ...)

De cette façon, vous n'avez pas besoin d'écrire explicitement le type, le framework le récupère automatiquement à partir de l'instance.

4voto

Rob Levine Points 20793

Vous ne pouvez pas l'utiliser de la manière que vous décrivez. L'intérêt des types génériques est que, même si vous ne les connaissez pas au moment du codage, le compilateur doit être capable de les résoudre au moment de la compilation. Pourquoi ? Parce que sous le capot, le compilateur va créer un nouveau type (parfois appelé type générique fermé) pour chaque utilisation différente du type générique "ouvert".

En d'autres termes, après la compilation,

DoesEntityExist<int>

est un type différent de

DoesEntityExist<string>

C'est ainsi que le compilateur est capable d'assurer la sécurité des types au moment de la compilation.

Pour le scénario que vous décrivez, vous devez passer le type comme un argument qui peut être examiné au moment de l'exécution.

L'autre option, comme mentionné dans d'autres réponses, est d'utiliser la réflexion pour créer le type fermé à partir du type ouvert, bien que cela soit probablement recommandé dans tout ce qui n'est pas des scénarios de niche extrême, je dirais.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X