2014-07-06 2 views
0

Pourquoi mon dictionnaire dit-il qu'une clé n'existe pas lorsque je viens de l'insérer? Est-ce à voir avec ma méthode Equals ou une double comparaison?La clé du dictionnaire est introuvable lorsqu'elle existe

Voici le code:

// Test: I know the dictionary contains nCoord but its saying the key doesn't exist 
Dictionary<UTMCoordinate, int> planes = new Dictionary<UTMCoordinate, int>(); 
UTMCoordinate nCoord = new UTMCoordinate(337394.136407966, 6263820.40182064, 0, 56, UTMCoordinate.Hemisphere.H_SOUTHERN); 
planes[nCoord]   = 1; 

bool exists = planes.ContainsKey(nCoord); // always returns false 

Ma mise en œuvre de UTMCoordinate est ci-dessous:

public class UTMCoordinate 
{ 
    public enum     Hemisphere {H_NOTHERN, H_SOUTHERN}; 
    public const double   DIF_TOLERANCE = 0.0005; 
    public double    x    { get; set; } 
    public double    y    { get; set; } 
    public double    elev   { get; set; } 
    public uint     UTMZone   { get; set; } 
    public Hemisphere   hemisphere  { get; set; } 

    public UTMCoordinate(double x, double y, double elev=double.MinValue, uint utmZone=uint.MinValue, Hemisphere hemisphere=Hemisphere.H_SOUTHERN) { 
     this.x   = x; 
     this.y   = y; 
     this.elev  = elev; 
     this.UTMZone = utmZone; 
     this.hemisphere = hemisphere; 
    } 

    public override int GetHashCode() { 
     unchecked // Overflow is fine, just wrap 
     { 
      int hash = 17; 
      // Suitable nullity checks etc, of course :) 
      hash = hash * 23 + x.GetHashCode(); 
      hash = hash * 23 + y.GetHashCode(); 
      hash = hash * 23 + elev.GetHashCode(); 
      hash = hash * 23 + UTMZone.GetHashCode(); 
      hash = hash * 23 + hemisphere.GetHashCode(); 
      return hash; 
     } 
    } 

    public override bool Equals(object obj) 
    { 
     UTMCoordinate other = obj as UTMCoordinate; 
     if (other == null) 
      return false; 

     return double.Equals(x, other.x) && double.Equals(y, other.y) && double.Equals(elev, other.elev) && uint.Equals(UTMZone, other.UTMZone) && double.Equals(hemisphere, other.hemisphere); 
    } 
} 

Modifier avec Daniel A. conseils Whites Je l'ai utilisé une méthode double comparaison différente. Malheureusement, son toujours pas identifier la clé:

public override bool Equals(object obj) 
{ 
    //return base.Equals (obj); 
    UTMCoordinate other = obj as UTMCoordinate; 
    if (other == null) 
     return false; 

    //return double.Equals(x, other.x) && double.Equals(y, other.y) && double.Equals(elev, other.elev) && uint.Equals(UTMZone, other.UTMZone) && double.Equals(hemisphere, other.hemisphere); 
    return Math.Abs (x-other.x) <= DIF_TOLERANCE && Math.Abs (y-other.y) <= DIF_TOLERANCE && Math.Abs (elev-other.elev) <= DIF_TOLERANCE && uint.Equals(UTMZone, other.UTMZone) && hemisphere == other.hemisphere; 
} 
+0

Les doubles fyi n'ont pas de précision fixe. Cela pourrait vous donner une idée. –

+0

Mettez un point d'arrêt sur les deux méthodes. Est-ce qu'ils sont appelés quand vous vous attendez? Est-ce qu'ils retournent les valeurs que vous attendez? –

+2

Je viens d'essayer. 'planes.ContainsKey (nCoord)' returened 'true' pour moi. – AlexD

Répondre

3

Si je prends votre code de votre question:

Dictionary<UTMCoordinate, int> planes = new Dictionary<UTMCoordinate, int>(); 
UTMCoordinate nCoord = new UTMCoordinate(337394.136407966, 6263820.40182064, 0, 56, UTMCoordinate.Hemisphere.H_SOUTHERN); 
planes[nCoord]   = 1; 

bool exists = planes.ContainsKey(nCoord); 

La valeur que je reçois pour exists est true.

Cependant, si je fais ceci:

nCoord.x = 1.0; 
exists = planes.ContainsKey(nCoord); 

La valeur de exists devient soudainement false même si l'objet est encore dans le dictionnaire. C'est parce que la valeur pour GetHashCode a changé. C'était -1473667404, mais après l'attribution de la propriété x il devient 201352392. Le dictionnaire utilise la valeur GetHashCode pour déterminer le compartiment dans lequel placer la clé. Ainsi, lorsque le code de hachage change, le dictionnaire peut essayer de trouver la clé dans le mauvais compartiment, puis signale qu'il ne contient pas la clé. Je soupçonne dans votre code ce qui se passe.

Vous devez donc changer votre objet afin qu'il soit immuable.

public double    x    { get; private set; } 
public double    y    { get; private set; } 
public double    elev   { get; private set; } 
public uint     UTMZone   { get; private set; } 
public Hemisphere   hemisphere  { get; private set; } 

Ensuite, ne modifiez AUCUNE des valeurs en dehors du constructeur.

Questions connexes