我有一个字典,其中键是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());
答案 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)
对于不覆盖Equals
和GetHashCode
方法的类,比较算法将默认引用相等而不是值相等。因此,尽管类实例的值字段/属性的值可能相同,但实例本身是不同的,因此相等性失败。
在这种情况下,除非为此类定义IEqualityComparer<XYZ>
实现,否则基本上不能将此类用作字典中的键。看看this answer by @Konrad Kokosa
答案 2 :(得分:0)
正如您所正确观察的那样,如果XYZ类尚未实现Equals
和GetHashCode
方法,那么它将进行引用比较(仅当它们引用堆上的同一对象时才为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
}