我正在存儲一個表示向量之間的距離矩陣的二維數組,作爲Dictionary<DistanceCell, double>
。我的DistanceCell
的實現有兩個字符串字段,表示被比較的向量。當密鑰存在時,C#字典會拋出KeyNotFoundException
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
循環遍歷字典時檢索到的,然後它檢索一個爲空的密鑰,然後嘗試調用Equals()
。我懷疑這與我的GetHashCode()
實施中的錯誤有關,但我不積極。還要注意,由於算法的性質,當我檢查它時,不應該存在字典中不存在密鑰的情況。該算法在每次執行時採用相同的路徑。
更新
我只是想通知大家,這個問題是固定的。事實證明,它與我的Equals()或GetHashCode()實現無關。我做了一些大量的調試,發現我得到一個KeyNotFoundException的原因是因爲密鑰在字典中並不存在,這很奇怪,因爲我肯定它正在被添加。問題在於我將密鑰添加到帶有多個線程的字典中,並且據此,c#Dictionary類不是線程安全的。所以時間一定是完美的,一個Add()失敗了,因此密鑰從未被添加到字典中。我相信這也可以解釋foreach循環如何偶爾創建一個空鍵。來自多個線程的Add()必須已經混淆了字典中的一些內部結構並引入了一個空鍵。
感謝各位的幫助!我很抱歉,它最終導致了我的錯誤。
您的'DistanceCell'類不是'sealed'。你確定沒有人從'DistanceCell'派生出來嗎?你的'Equals'方法不檢查'obj'或'cell'是否是'this'的多派生類型(反之亦然)。你應該包括這些支票,或者將你的班級標記爲「密封」。 –
@Jeppe我沒有任何從'DistanceCell'派生的類,所以這不應該是一個問題,但我會將它標記爲'sealed'以保證安全。 – StrangerLoop
我有這個問題,但實際的原因是我有兩種不同類型的空間,由複製粘貼代碼進出excel單元格造成的。 – will