字典表示密钥在它存在时不存在

时间:2014-01-20 22:06:44

标签: c# autodesk

我有一个字典,其中键是XYZ个对象,值是boolean。 XYZ类来自Autodesks API,因此它不是我制作的类。我试图检查字典中是否存在密钥。

我的问题:如果字典包含密钥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 个答案:

答案 0 :(得分: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的实施仅仅是示范性的。阅读What is the best algorithm for an overridden System.Object.GetHashCode?以获得更好的替代方案。

答案 1 :(得分:1)

对于不覆盖EqualsGetHashCode方法的类,比较算法将默认引用相等而不是值相等。因此,尽管类实例的值字段/属性的值可能相同,但实例本身是不同的,因此相等性失败。

在这种情况下,除非为此类定义IEqualityComparer<XYZ>实现,否则基本上不能将此类用作字典中的键。看看this answer by @Konrad Kokosa

答案 2 :(得分:0)

正如您所正确观察的那样,如果XYZ类尚未实现EqualsGetHashCode方法,那么它将进行引用比较(仅当它们引用堆上的同一对象时才为true)

由于您无权访问该类,因此将其包装在您自己的类中,您可以在其中编写一个使用XYZ内容进行正确比较的Equals方法。

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
}