Pourquoi ne puis-je pas comparer un KeyValuePair avec default

.Net de 2,5 je peux habituellement obtenir une comparaison d'égalité (==) entre une valeur et son type par défaut

if (myString == default(string))

cependant j'obtiens l'exception suivante quand j'essaye d'exécuter une comparaison d'égalité sur un KeyValuePair par défaut et un KeyValuePair

Exemple de Code (à partir d'une pré-extension de la méthode, de la proto-lambda statique ListUtilities classe :) )

public static TKey 
        FirstKeyOrDefault<TKey, TValue>(Dictionary<TKey, TValue> lookups, 
                   Predicate<KeyValuePair<TKey, TValue>> predicate)
{
    KeyValuePair<TKey, TValue> pair = FirstOrDefault(lookups, predicate);

    return pair == default(KeyValuePair<TKey, TValue>) ? 
                   default(TKey) : pair.Key;
}

Exception:

<!-L'opérateur '= = ' ne peut pas être appliqué à des opérandes de type 'Système.Collection.Générique.KeyValuePair" et 'Système.Collection.Générique.KeyValuePair '

est-ce parce que, en tant que Structure, Le Keynvaluepair n'est pas nul? Si c'est le cas, pourquoi, comme, sans doute, default a-t-il été implémenté pour traiter les types non nulles?

EDIT

pour rappel, j'ai choisi @Chris Hannon comme réponse choisie, car il m'a donné ce que je cherchais, l'option la plus élégante, et un explication succincte, cependant j'encourage la lecture de @Dasuraga pour une explication très complète sur la raison pour laquelle c'est le cas

31
demandé sur johnc 2011-06-17 03:47:37

6 réponses

Cela se produit parce que KeyValuePair<TKey, TValue> ne définit pas une coutume opérateur == et n'est pas inclus dans la liste prédéfinie des types de valeur qui peut l'utiliser.

Voici un lien vers le MSDN documentation pour l'opérateur.

pour les types de valeurs prédéfinis, l'opérateur d'égalité (==) renvoie true si les valeurs de ses opérandes sont égales, false autrement.

Votre meilleur pari pour un contrôle d'égalité dans ce cas, parce que ce n'est pas un struct vous avez plus de contrôle, c'est d'appeler default(KeyValuePair<TKey,TValue>).Equals(pair) à la place.

51
répondu Chris Hannon 2011-06-17 00:03:25

(Si vous n'avez pas de soins sur les génériques de discussion lié à cette erreur, vous pouvez simplement sauter à la fin de votre "vraie" réponse)

comme le dit l'erreur, il n'y a pas de test d'égalité pour KeyValuePairs (i.e. il n'y a pas de méthode de comparaison intégrée). La raison en est d'éviter d'imposer des contraintes sur les types de valeurs clés (il y a de nombreux cas où des comparaisons de valeurs clés ne seraient jamais effectuées).

évidemment, si vous voulez comparer ces valeurs clés, je le ferais imaginez ce que vous voulez est de vérifier si les clés et les valeurs sont égales. Mais cela implique tout un tas de choses , notamment que TKey et TValue sont deux types comparables (c'est-à-dire qu'ils implémentent L'interface IComparable)

Vous pouvez écrire votre propre fonction de comparaison entre keyvaluepairs, par exemple:

static bool KeyValueEqual<TKey , TValue>(KeyValuePair<TKey, TValue> fst, 
                                          KeyValuePair<TKey, TValue> snd) 
                                         where  TValue:IComparable
                                         where  TKey:IComparable
        {
            return (fst.Value.CompareTo(snd.Value)==0)
                     && (snd.Key.CompareTo(fst.Key)==0);
        }

(Excusez le terrible indentation)

ici, nous imposons que TKey et TValue sont toutes deux comparables (via le membre CompareTo). fonction.)

la fonction CompareTo (telle que définie pour les types prédéfinis) renvoie 0 lorsque deux objets sont égaux , à la strcmp . A. ComparesTo(b)==0 signifie que a et b sont les "mêmes"(en valeur, pas le même objet).

de sorte que cette fonction devrait prendre deux KVPs (k,v) et (k',v') renvoie true si et seulement si k==k' et v==v' (au sens intuitif).


Mais est-ce nécessaire? Il semble que votre test où vous avez des problèmes est basé sur certains une sorte de vérification au retour de FirstOrDefault.

mais il y a une raison pour laquelle votre fonction s'appelle FirstOrDefault:

Renvoie le premier élément de la séquence qui satisfait à une condition ou par défaut valeur aucun élément est trouver.

(l'emphase est mienne)

Cette fonction retourne les valeurs par défaut si quelque chose n'est pas trouvé, ce qui signifie que votre prédicate n'est pas vérifié,vous obtiendrez une valeur KeyValuePair égale à (default(TKey), default(TValue).

votre code donc (intention de) vérifier si paire.Key==défaut(TKey), seulement retour par défaut(TKey) de toute façon. Ça n'aurait pas plus de sens de retourner la paire?Clé dès le début?

5
répondu rtpg 2011-06-17 00:19:44

pour utiliser l'opérateur d'égalité "= = " sur n'importe quelle classe ou structure, il doit surcharger l'opérateur:http://msdn.microsoft.com/en-us/library/ms173147 (v = 80).aspx

KeyValuePair ne le fait pas, et donc vous obtenez l'erreur de compilation. Remarque, vous obtiendrez le même message d'erreur si vous essayez ceci:

var k1 = new KeyValuePair<int,string>();
var k2 = new KeyValuePair<int,string>();

bool b = k1 == k2; //compile error

EDIT: comme Eric Lippert m'a corrigé dans les commentaires, les classes n'ont évidemment pas besoin d'outrepasser l'opérateur d'égalité pour "= = " pour être valide. Il compilera fine et fera une vérification de l'égalité des références. Mon erreur.

3
répondu BFree 2011-06-17 02:31:08

Il ne parvient pas pour la même raison que la suivante:

var kvp = new KeyValuePair<string,string>("a","b");
var res = kvp == kvp;

L'indice est dans le message d'erreur, naturellement. (Il n'a rien à voir avec