[英]implement GetHashCode() for objects that contain collections
考慮以下對象:
class Route
{
public int Origin { get; set; }
public int Destination { get; set; }
}
Route實現了相等運算符。
class Routing
{
public List<Route> Paths { get; set; }
}
我使用下面的代碼為Routing對象實現GetHashCode方法,它似乎工作,但我想知道這是否是正確的方法呢? 我依靠平等檢查,因為我不確定我以為我會問你們。 我可以只是總結哈希碼還是我需要做更多的魔法以保證所需的效果?
public override int GetHashCode() =>
{
return (Paths != null
? (Paths.Select(p => p.GetHashCode())
.Sum())
: 0);
}
我在這里檢查了幾個GetHashCode()
問題,以及MSDN和Eric Lippert關於這個主題的文章,但是找不到我想要的東西。
我認為您的解決方案很好。 (后來很多評論:LINQ的Sum
方法將在checked
上下文中起作用,因此你可以很容易地得到一個OverflowException
,這意味着它畢竟不是那么好。)但是更常見的是做XOR(不帶進位的加法)。 所以它可能是這樣的
public override int GetHashCode()
{
int hc = 0;
if (Paths != null)
foreach (var p in Paths)
hc ^= p.GetHashCode();
return hc;
}
附錄(接受答復后):
請記住,如果您在Dictionary<Routing, Whatever>
, HashSet<Routing>
或使用哈希表的其他情況下使用此類型Routing
,那么如果有人在Routing
后更改(變更) Routing
,則您的實例將丟失已添加到集合中。
如果您確定永遠不會發生,請使用上面的代碼。 如果確保沒有人改變引用的Routing
, Dictionary<,>
等仍然有效。
另一個選擇就是寫
public override int GetHashCode()
{
return 0;
}
如果您認為永遠不會使用哈希碼。 如果每個instace都為哈希代碼返回0
,那么使用哈希表會得到非常糟糕的性能,但是你的對象不會丟失。 第三種選擇是拋出NotSupportedException
。
來自Jeppe Stig Nielsen的答案的代碼可行,但它可能會導致大量重復哈希碼值。 假設您正在哈希一個0-100范圍內的整數列表,那么您的哈希碼將被保證在0到255之間。這在字典中使用時會產生大量沖突。 這是一個改進版本:
public override int GetHashCode()
{
int hc = 0;
if (Paths != null)
foreach (var p in Paths) {
hc ^= p.GetHashCode();
hc = (hc << 7) | (hc >> (32 - 7)); //rotale hc to the left to swipe over all bits
}
return hc;
}
隨着越來越多的項目被散列,此代碼將至少涉及所有位。
作為指導原則,對象的哈希值必須與對象的整個生命周期相同。 我會單獨留下GetHashCode
函數,而不是覆蓋它。 僅當您要將對象放在哈希表中時才使用哈希碼。
您應該閱讀Eric Lippert關於.NET中哈希碼的精彩文章: GetHashCode的指南和規則 。
引用該文章:
准則:GetHashCode返回的整數永遠不會改變
規則:當對象包含在依賴於哈希代碼保持穩定的數據結構中時,GetHashCode返回的整數必須永遠不會更改
如果對象的哈希代碼在哈希表中變異,那么顯然Contains方法就會停止工作。 你把對象放在#5桶中,你改變它,當你問集合是否包含變異對象時,它會在#74桶中查找並找不到它。
您實現的GetHashCode
函數將不會在對象的生命周期內返回相同的哈希代碼。 如果使用此函數,如果將這些對象添加到哈希表中,則會遇到麻煩: Contains
方法不起作用 。
我認為這不是一種正確的方法,因此必須確定最終的hashcode
它必須對指定的對象是唯一的。 在您的情況下,您執行Sum()
,它可以在集合中使用不同的哈希碼生成相同的結果(在末尾哈希碼只是整數)。
如果您的目的是根據集合的內容確定相等性,那么只需比較兩個對象之間的這些切片。 順便說一句,這可能是耗時的操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.