2010-03-05 8 views
1

Je ne trouve pas d'entrée de dictionnaire par clé. J'ai une interface comme ce qui suit:Impossible de trouver la clé dans le dictionnaire générique

public interface IFieldLookup 
{ 
    string FileName { get; set; } 
    string FieldName { get; set; } 
} 

, j'ai un dictionnaire comme ceci:

Dictionary<IFieldLookup, IField> fd 

Lorsque je tente de récupérer un élément du dictionnaire par la clé, je reçois un KeyNotFoundException. Je suppose que je dois mettre en place un certain type de comparaison - si mon hypothèse est correcte, quelle est la façon recommandée de mettre en œuvre une comparaison dans ce cas?

+0

À quoi ressemblent les classes qui implémentent IFieldLookup? Est-ce qu'ils remplacent les méthodes Equals et/ou GetHashCode? – Nick

+0

@Nick - ils ne le font pas - actuellement, ils implémentent uniquement les deux propriétés dans l'interface IFieldLookup. – dugas

+0

@ Merci à tous pour les commentaires. – dugas

Répondre

1

Depuis cette est une interface plutôt qu'une classe, vous devrez définir votre opérateur d'égalité pour chaque classe qui implémente l'interface. Et ces opérateurs devront fonctionner de manière cohérente. (Ce serait beaucoup mieux si c'était une classe plutôt qu'une interface.)

Vous devez remplacer les méthodes Equals(object) et GetHashCode() sur chaque classe.

Probablement quelque chose comme ceci:

public override bool Equals(object obj) 
{ 
    IFieldLookup other = obj as IFieldLookup; 
    if (other == null) 
     return false; 
    return other.FileName.Equals(this.FileName) && other.FieldName.Equals(this.FieldName); 
} 

public override int GetHashCode() 
{ 
    return FileName.GetHashCode() + FieldName.GetHashCode(); 
} 

ou ceci:

public override bool Equals(object obj) 
{ 
    IFieldLookup other = obj as IFieldLookup; 
    if (other == null) 
     return false; 
    return other.FileName.Equals(this.FileName, StringComparison.InvariantCultureIgnoreCase) && other.FieldName.Equals(this.FieldName, StringComparison.InvariantCultureIgnoreCase); 
} 

public override int GetHashCode() 
{ 
    return StringComparer.InvariantCulture.GetHashCode(FileName) + 
      StringComparer.InvariantCulture.GetHashCode(FieldName); 
} 

Selon la façon dont vous voulez qu'il se comporte.

+0

-1: Puisque la comparaison est spécifique à ce dictionnaire, utilisez à la place le 'IEqualityComparer ' nécessaire. –

+0

@ 280Z28 - L'OP n'indique pas que la comparaison sera spécifique à ce dictionnaire. Il est très probable que la comparaison aura d'autres utilisations dans le programme, et la sémantique de ces utilisations doit être la même .. –

+0

Je comprends ce que disent @Jeffrey et @ 280Z28.L'extrait de la page MSDN de IEquatable résume bien: L'interface IEquatable <(Of <(T>)> définit l'égalité sur le type lui-même, tandis qu'une interface IEqualityComparer <(Of <(T>)> est externe au type et permet de nombreuses implémentations différentes à être utilisé pour le même type. Merci à vous deux pour votre contribution. – dugas

4

utilisation ContainsKey et surchargent equals sur la classe clé

Ok permet de dire que ceci est notre classe clé:

class Key 
{ 
    public int KeyValue; 
    public override Equals(object o) 
    { 
    return ((Key)o).KeyValue == KeyValue); 
    } 
} 

permet maintenant d'utiliser la classe comme

clé
Dictonary<Key, string> dict = new Dictonary<Key, string>(); 
Key k = new Key(); 
k.KeyValue = 123; 
dict.Add(k, "Save me!"); 
Key k2 = new Key(); 
k2.KeyValue = 123; 
if (dict.ContainsKey(k2)) 
{ 
    string value = dict[k2]; 
} 
+4

C'est la partie "override equals" qui est importante ici. –

+0

@Petoj - vous dites d'utiliser le ContainsKey - pouvez-vous expliquer? Est-ce que vous le recommandez pour que je ne reçoive pas l'exception? Si c'est le cas, j'aimerais une exception dans cette situation. – dugas

+0

-1: Utilisez 'IEqualityComparer ' à la place. –

1

Mettre en oeuvre une instance de IEqualityComparer<T> (recommandé en dérivant de EqualityComparer<T> pour sa mise en œuvre automatique de IEqualityComparer ainsi) pour le type de clé, et passer une instance au constructeur dictionnaire. De cette façon, vous pouvez implémenter la comparaison de manière cohérente sur plusieurs implémentations de l'interface.

+0

-1 Cela comporte le risque que des comparateurs d'égalité inconsistants soient utilisés dans des opérations n'impliquant pas ce dictionnaire spécifique. –

+0

@ 280Z28 - après avoir lu ces interfaces, je vois MSDN dit que le EqualityComparer ) .Default propriété: « vérifie si le type T implémente l'interface générique System.IEquatable et, le cas échéant, retourne un EqualityComparer ) qui contient les Implémentation de la méthode IEquitableEquals, sinon, elle renvoie un EqualityComparer ), tel que fourni par T. " Donc je devine que la bonne chose à faire est d'implémenter IEquatable et d'utiliser le EqualityComparer .Default et dans le cas d'avoir besoin d'une comparaison différente alors dériver de EqualityComparer ? – dugas

+0

Pour ce dictionnaire, vous n'utilisez pas la valeur par défaut 'EqualityComparer ' - c'est ce que 'Dictionary ' utilise si vous ne spécifiez pas de comparateur personnalisé. –

Questions connexes