簡體   English   中英

為包含集合的對象實現GetHashCode()

[英]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 ,則您的實例將丟失已添加到集合中。

如果您確定永遠不會發生,請使用上面的代碼。 如果確保沒有人改變引用的RoutingDictionary<,>等仍然有效。

另一個選擇就是寫

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM