我正在存储一个二维数组,它表示向量之间的距离矩阵作为 Dictionary<DistanceCell, double>
.我的实现 DistanceCell
有两个字符串字段代表被比较的向量。
class DistanceCell
{
public string Group1 { get; private set; }
public string Group2 { get; private set; }
public DistanceCell(string group1, string group2)
{
if (group1 == null)
{
throw new ArgumentNullException("group1");
}
if (group2 == null)
{
throw new ArgumentNullException("group2");
}
this.Group1 = group1;
this.Group2 = group2;
}
}
因为我使用这个类作为键,所以我覆盖了 Equals()
和 GetHashCode()
:
public override bool Equals(object obj)
{
// False if the object is null
if (obj == null)
{
return false;
}
// Try casting to a DistanceCell. If it fails, return false;
DistanceCell cell = obj as DistanceCell;
if (cell == null)
{
return false;
}
return (this.Group1 == cell.Group1 && this.Group2 == cell.Group2)
|| (this.Group1 == cell.Group2 && this.Group2 == cell.Group1);
}
public bool Equals(DistanceCell cell)
{
if (cell == null)
{
return false;
}
return (this.Group1 == cell.Group1 && this.Group2 == cell.Group2)
|| (this.Group1 == cell.Group2 && this.Group2 == cell.Group1);
}
public static bool operator ==(DistanceCell a, DistanceCell b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If either is null, return false.
// Cast a and b to objects to check for null to avoid calling this operator method
// and causing an infinite loop.
if ((object)a == null || (object)b == null)
{
return false;
}
return (a.Group1 == b.Group1 && a.Group2 == b.Group2)
|| (a.Group1 == b.Group2 && a.Group2 == b.Group1);
}
public static bool operator !=(DistanceCell a, DistanceCell b)
{
return !(a == b);
}
public override int GetHashCode()
{
int hash;
unchecked
{
hash = Group1.GetHashCode() * Group2.GetHashCode();
}
return hash;
}
如您所见,DistanceCell
的要求之一是那个Group1
和 Group2
是可以互换的。所以对于两个字符串 x
和 y
, DistanceCell("x", "y")
必须等于 DistanceCell("y", "x")
.这就是我实现 GetHashCode()
的原因乘法因为DistanceCell("x", "y").GetHashCode()
必须等于 DistanceCell("y", "x").GetHashCode()
.
我遇到的问题是它在大约 90% 的时间内都可以正常工作,但会抛出 KeyNotFoundException
或 NullReferenceException
剩下的时间。前者在从字典中获取键时抛出,后者在我使用 foreach
遍历字典时抛出。循环并检索一个为 null 的键,然后尝试调用 Equals()
上。我怀疑这与我的 GetHashCode()
中的错误有关实现,但我不是积极的。另请注意,由于算法的性质,当我检查字典时,绝不会出现 key 不存在的情况。该算法每次执行都采用相同的路径。
更新
我只是想告诉大家这个问题已经解决了。事实证明,它与我的 Equals() 或 GetHashCode() 实现无关。我做了一些广泛的调试,发现我得到 KeyNotFoundException 的原因是因为字典中根本不存在该键,这很奇怪,因为我确信它被添加了。问题是我用多个线程将键添加到字典中,据此,c# Dictionary 类不是线程安全的。所以 Add() 失败的时机一定是完美的,因此 key 从未被添加到字典中。我相信这也可以解释 foreach 循环是如何偶尔产生一个空键的。来自多个线程的 Add() 一定弄乱了字典中的一些内部结构并引入了一个空键。
感谢大家的帮助!很抱歉,这完全是我的错。
最佳答案
看看this blog post作者:埃里克·利珀特
它表示即使更改对象的内容,GetHashCode 的结果也永远不会改变。原因是 Dictionary 使用桶来加快索引速度。更改 GetHasCode 结果后,Dictionary 将无法为您的对象找到正确的存储桶,这可能导致“找不到键”
我可能是错的,但值得测试。
关于C# 字典在键存在时抛出 KeyNotFoundException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14428668/