字典键存在时找不到

saz*_*azr 1 c# dictionary double-precision

为什么我的字典在我刚插入时说密钥不存在?是跟我的Equals方法还是双重比较有关?

这是代码:

// 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
Run Code Online (Sandbox Code Playgroud)

我的实现UTMCoordinate如下:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用 Daniel A. Whites 的建议进行编辑我使用了不同的双重比较方法。不幸的是,它仍然没有确定密钥:

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;
}
Run Code Online (Sandbox Code Playgroud)

Eni*_*ity 5

如果我从你的问题中取出你的代码:

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);
Run Code Online (Sandbox Code Playgroud)

我得到的价值existstrue

但是,如果我这样做:

nCoord.x = 1.0;
exists = planes.ContainsKey(nCoord);
Run Code Online (Sandbox Code Playgroud)

即使对象仍在字典中,它的值也会exists突然变为false。这是因为 的值GetHashCode已更改。是的-1473667404,但在分配财产后,x它变成了201352392

字典使用 的值GetHashCode来确定将键放入哪个桶,因此当哈希码更改时,字典可能会尝试在错误的桶中查找键,然后报告它不包含该键。

我怀疑在您的代码中发生了这种情况。

所以你需要改变你的对象,使其不可变。

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; }
Run Code Online (Sandbox Code Playgroud)

然后不要更改构造函数之外的任何值。