2010-09-03 8 views
8

Je viens de rencontrer cette situation et j'ai pensé que c'était une bonne opportunité d'utiliser le mot clé par défaut. Mais il ne compile pas et je ne peux pas penser à pourquoi. L'exemple ci-dessous illustre mon problème:La comparaison d'un type générique avec sa valeur par défaut, sans contrainte de classe générique, donne une erreur de compilation

public class Test<TDataSource> 
{ 
    public IQueryable<TDataSource> DataSource { get; set; } 

    public bool GetOneOrDefaultResult() 
    { 
     var result = DataSource.SingleOrDefault(); 
     return result != default(TDataSource); 
    } 
} 

Vous obtiendrez une erreur sur la ligne 8 (« opérateur « == » ne peut pas être appliqué aux opérandes de type « TDataSource » et « TDataSource ». »). Je pensais que l'utilisation du mot-clé par défaut éliminerait tout problème de comparaison entre les types de référence et les types de valeur. L'ajout d'une contrainte générique limitant TDataSource aux types de référence permet de compiler ce morceau de code. Est-ce que quelqu'un peut expliquer pourquoi le compilateur ne résoudra pas cela pour moi? Est-ce que ce n'est pas assez intelligent pour voir ça fonctionnerait?

Ceci est lié: Can't operator == be applied to generic types in C#?

[Modifier] de réponse m'a donné un peu d'inspiration, l'opérateur '==' ne fonctionnera pas, mais la fonction Equals devrait le faire.

public class Test<TDataSource> 
{ 
    public IQueryable<TDataSource> DataSource { get; set; } 

    public bool GetOneOrDefaultResult() 
    { 
     var result = DataSource.SingleOrDefault(); 
     return result.Equals(default(TDataSource)); 
    } 
} 

Cette compilation devrait-elle fonctionner correctement?

+0

Si vous essayez juste de comprendre s'il y avait un résultat, vous le faites mal parce que vous ne serez pas capable de faire la différence entre aucun résultat et le résultat étant 0. – Gabe

+0

Gabe la logique de la La fonction n'est qu'un exemple, ce n'est pas utile. – JJoos

+1

Votre modification peut lancer une exception NullReferenceException. Vous devez appeler la méthode statique 'Equals (a, b)'. – SLaks

Répondre

5

Vous ne pouvez pas supposer que chaque type de valeur remplace l'opérateur ==. (Et même si elles le faisaient, il n'y aurait pas moyen d'appeler à l'aide de médicaments génériques, il est une méthode statique)

Au lieu de cela, vous devez écrire

return !(ReferenceEquals((object)result, (object)default(TDataSource)) 
      || result.Equals(default(TDataSource))); 

Si result est null (et un type de référence), l'appel ReferenceEquals renverra true, donc Equals ne sera pas appelé et ne lancera pas NullReferenceException.
Si TDataSource est un type de valeur, le ReferenceEquals va comparer deux références encadrées différentes (qui peuvent contenir la même valeur, mais seront toujours différentes), donc il passera à l'appel Equals.

+0

Remarque En général, c'est ainsi que vous devez comparer deux valeurs de type inconnu pour l'égalité. (c'est-à-dire que ceci ne s'applique pas uniquement à la recherche de valeurs par défaut) – Gabe

+0

Vous avez absolument raison. Ces seules structures définies par l'utilisateur ne remplacent-elles pas l'opérateur '=='? – JJoos

+0

@JJoos, si les types de valeur remplacent l'opérateur '==', il est recommandé de surcharger 'Equals()' pour qu'il se comporte de manière équivalente. Ce n'est pas strictement garanti, mais je considérerais cela comme un bug si je trouve un type de valeur qui ne se comporte pas de cette façon. –

Questions connexes