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

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

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

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

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

Je continue à recevoir l’erreur de compilation suivante:

Le type ou le nom de l’espace de noms ‘t’ est introuvable (manque-t-il une directive using ou une référence d’assembly?)

 DoesEntityExist(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.

Le point sur les génériques est de donner une sécurité de type à la compilation – ce qui signifie que les types doivent être connus à la compilation.

Vous pouvez appeler des méthodes génériques avec des types uniquement connus au moment de l’exécution, mais vous devez utiliser la reflection:

 // 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, à la place, rendre votre méthode d’ appel générique et passer votre paramètre de type en tant qu’argument de type, en poussant la décision d’un niveau plus haut dans la stack?

Si vous pouviez nous donner plus d’informations sur ce que vous faites, cela aiderait. Parfois, vous devrez peut-être utiliser la reflection comme ci-dessus, mais si vous choisissez le bon point, vous pouvez vous assurer que vous ne devez le faire qu’une fois, et que tout ce qui se trouve en dessous utilise le paramètre type de manière normale.

Une façon de contourner ce problème est d’utiliser la diffusion implicite:

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

l’appelant ainsi:

 DoesEntityExist(entity, entityGuid, transaction); 

En allant plus loin, vous pouvez le transformer en une méthode d’extension (il faudra la déclarer dans une classe statique):

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

appelant ainsi:

 entity.DoesEntityExist(entityGuid, transaction); 

Je ne sais pas si je comprends bien votre question, mais vous pouvez écrire votre code de cette manière:

bool DoesEntityExist(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 dépassera automatiquement le type à partir de l’instance.

Vous ne pouvez pas l’utiliser comme vous le décrivez. Le point concernant les types génériques est que, bien que vous ne les connaissiez pas au «temps de codage», le compilateur doit être capable de les résoudre au moment de la compilation. Pourquoi? Parce que sous le capot, le compilateur disparaîtra et créera 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 compilation,

 DoesEntityExist 

est un type différent de

 DoesEntityExist 

C’est ainsi que le compilateur est en mesure d’exercer une sécurité de type à la compilation.

Pour le scénario que vous décrivez, vous devez transmettre le type en tant qu’argument pouvant être examiné au moment de l’exécution.

L’autre option, mentionnée dans d’autres réponses, consiste à utiliser la reflection pour créer le type fermé à partir du type ouvert, bien que cela soit probablement recommandé dans des scénarios de niche extrêmes.