J'ai pu trouver un Article sur Microsoft Connect qui traite de cette question en détail :
Malheureusement, ce comportement est dû à la conception et il n'existe pas de solution simple pour permettre l'utilisation de paramètres de type avec qui peuvent contenir des types de valeurs.
Si les types sont connus pour être des types de référence, la surcharge par défaut de defined on object teste les variables pour l'égalité de référence, bien qu'un type puisse spécifier sa propre surcharge personnalisée. Le compilateur détermine la surcharge à utiliser en fonction du type statique de la variable (la détermination n'est pas polymorphe). Par conséquent, si vous modifiez votre exemple pour contraindre le paramètre de type générique T à un type de référence non scellé (tel que Exception), le compilateur peut déterminer la surcharge spécifique à utiliser et le code suivant sera compilé :
public class Test<T> where T : Exception
Si les types sont connus pour être des types de valeur, effectue des tests d'égalité de valeur spécifiques basés sur les types exacts utilisés. Il n'y a pas de bonne comparaison "par défaut" ici puisque les comparaisons de référence n'ont pas de sens sur les types de valeur et que le compilateur ne peut pas savoir quelle comparaison de valeur spécifique émettre. Le compilateur pourrait émettre un appel à ValueType.Equals(Object) mais cette méthode utilise la réflexion et est assez inefficace par rapport aux comparaisons de valeurs spécifiques. Par conséquent, même si vous deviez spécifier une contrainte de type de valeur sur T, le compilateur n'a rien de raisonnable à générer ici :
public class Test<T> where T : struct
Dans le cas que vous avez présenté, où le compilateur ne sait même pas si T est un type valeur ou référence, il n'y a de même rien à générer qui serait valide pour tous les types possibles. Une comparaison de référence ne serait pas valide pour les types valeur et une sorte de comparaison de valeur serait inattendue pour les types référence qui ne surchargent pas.
Voici ce que vous pouvez faire...
J'ai validé que ces deux méthodes fonctionnent pour une comparaison générique des types de référence et de valeur :
object.Equals(param, default(T))
ou
EqualityComparer<T>.Default.Equals(param, default(T))
Pour effectuer des comparaisons avec l'opérateur "==", vous devez utiliser l'une de ces méthodes :
Si tous les cas de T dérivent d'une classe de base connue, vous pouvez le faire savoir au compilateur en utilisant des restrictions de type génériques.
public void MyMethod<T>(T myArgument) where T : MyBase
Le compilateur reconnaît alors comment effectuer des opérations sur MyBase
et ne produira pas l'erreur "Operator '==' cannot be applied to operands of type 'T' and 'T'" que vous voyez actuellement.
Une autre option serait de restreindre T à tout type qui implémente IComparable
.
public void MyMethod<T>(T myArgument) where T : IComparable
Et ensuite utiliser le CompareTo
définie par la méthode Interface IComparable .
0 votes
C# prend désormais en charge Opérateurs conditionnels nuls qui est un sucre syntaxique pour le dernier exemple que vous donnez. Votre code deviendrait
if (myArgument?.Equals( default(T) ) != null )
.1 votes
@wizard07KSU Cela ne fonctionne pas pour les types de valeurs, c'est-à-dire que l'évaluation est égale à
true
en tout cas parce queEquals
sera toujours appelé pour les types de valeurs puisquemyArgument
ne peut êtrenull
dans ce cas et le résultat deEquals
(un booléen) ne sera jamaisnull
.0 votes
Un quasi-duplicata de valeur égale (donc pas de vote de proximité) : L'opérateur == ne peut-il pas être appliqué aux types génériques en C# ?