J'ai pu localiser un article Microsoft Connect qui traite de ce problème en détail:
Malheureusement, ce comportement est inhérent à la conception et il n'y a pas de solution facile pour permettre l'utilisation de paramètres de type pouvant contenir des types de valeur.
Si les types sont connus pour être des types de référence, la surcharge par défaut de défini sur l'objet 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 compile:
public class Test<T> where T : Exception
Si les types sont connus pour être des types de valeur, effectue des tests spécifiques d'égalité de valeur en fonction des types exacts utilisés. Il n'y a pas de bonne comparaison "par défaut" ici car les comparaisons de référence ne sont pas significatives sur les types de valeur et le compilateur ne peut pas savoir quelle comparaison de valeur spécifique émettre. Le compilateur peut é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 valeur sur T, il n'y a rien de raisonnable à générer ici par le compilateur:
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 une valeur ou un type de référence, il n'y a de même rien à générer qui serait valable pour tous les types possibles. Une comparaison de référence ne serait pas valide pour les types de valeur et une sorte de comparaison de valeur serait inattendue pour les types de 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 faire des comparaisons avec l'opérateur "==", vous devrez utiliser l'une de ces méthodes:
Si tous les cas de T dérivent d'une classe de base connue, vous pouvez informer le 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 lancera pas l'erreur "Operator '==' ne peut pas être appliquée aux opérandes de type" T "et" T "" que vous voyez maintenant.
Une autre option serait de restreindre T à tout type qui implémente IComparable
.
public void MyMethod<T>(T myArgument) where T : IComparable
Et puis utilisez la CompareTo
méthode définie par l' interface IComparable .
if (myArgument?.Equals( default(T) ) != null )
.