字典中说键不存在,但实际上存在该键。

3
我有一个字典,其中键是Autodesk API的XYZ对象,值是布尔值。我试图检查字典中是否存在一个键。
我的问题:如果字典包含键new XYZ(1,1,1),并且我使用myDictionary.ContainsKey(new XYZ(1,1,1))检查字典是否包含此键,则始终返回false。
为什么会这样发生,我该怎么办?我认为类XYZ需要实现它的Equals方法,但正如我之前提到的,我没有创建这个类,它是Autodesks API的一部分。或者我做错了什么?
Dictionary<XYZ, bool> prevPnts = new Dictionary<XYZ, bool>();
prevPnts[new XYZ(1,1,1)] = true;

// Always says the pnt doesnt exist?
if (prevPnts.ContainsKey(new XYZ(1,1,1)))
   TaskDialog.Show("Contains");
else TaskDialog.Show("NOT Contains");

使用Konrads答案的解决方案

class XYZEqualityComparer : IEqualityComparer<XYZ>
{
    public bool Equals(XYZ a, XYZ b)
    {
        if (Math.Abs(a.DistanceTo(b)) <= 0.05)
            return true;

        return false;
    }


    public int GetHashCode(XYZ x)
    {
        int hash = 17;
        hash = hash * 23 + x.X.GetHashCode();
        hash = hash * 23 + x.Y.GetHashCode();
        hash = hash * 23 + x.Z.GetHashCode();
        return hash;
    }
}

Dictionary<XYZ, bool> prevPnts = new Dictionary<XYZ, bool>(new XYZEqualityComparer());
3个回答

11

提供您自己的 IEqualityComparer 到字典中,因为它不知道如何比较 XYZ 类(严格来说,它通过引用进行比较):

class XYZEqualityComparer : IEqualityComparer<XYZ>
{
    public bool Equals(XYZ a, XYZ b)
    {
        return a.X == b.X && a.Y == b.Y && a.Z == b.Z;            
    }    

    public int GetHashCode(XYZ x)
    {
        int hash = x.X ^ x.Y ^ x.Z;
        return hash .GetHashCode();
    }
}

接着:

Dictionary<XYZ, bool> prevPnts = new Dictionary<XYZ, bool>(new XYZEqualityComparer());

注意:我的GetHashCode实现仅供参考。阅读“针对重写的System.Object.GetHashCode(),最佳算法是什么?”以获取更好的替代方案。


1
对于没有重写 EqualsGetHashCode 方法的类,比较算法将默认使用引用相等性而不是值相等性。因此,尽管类实例的值字段/属性的值可能相同,但实例本身是不同的,因此相等性失败。
在这种情况下,您基本上不能仅使用此类作为字典中的键,除非您为该类定义了一个 IEqualityComparer<XYZ> 实现。请看看 @Konrad Kokosa 的这个答案

是的,我在答案中注意到了。 - rae1
是的,我知道。谢谢提醒。 - rae1

0

正如您所观察到的那样,如果 XYZ 类没有实现 EqualsGetHashCode 方法,则它将执行引用比较(仅在它们引用堆上的同一对象时为真)。

解决此问题的方法之一是,由于您无法访问该类,因此可以将其包装在自己的类中,在其中编写一个 Equals 方法,该方法使用 XYZ 的内容进行适当的比较。

class WrapperXYZ
{
    XYZ xyz;

    public override bool Equals(object other)
    {
        if(other is typeof(XYZ))
        {
            // check the contents
        }
        else
        {
            return false;
        }
    }

    // TODO: write a hash method if you are using a dictionary
}

与其仅仅为了重写EqualsGetHashCode而包装类型,不如编写一个IEqualityComparer,它是专门设计用于定义其他类型的相等性。 - Servy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接