簡體   English   中英

GetHashCode在IEqualityComparer中的作用是什么<T>在.NET 中?

[英]What's the role of GetHashCode in the IEqualityComparer<T> in .NET?

我試圖了解接口 IEqualityComparer 的 GetHashCode 方法的作用。

以下示例取自 MSDN:

using System;
using System.Collections.Generic;
class Example {
    static void Main() {
        try {

            BoxEqualityComparer boxEqC = new BoxEqualityComparer();

            Dictionary<Box, String> boxes = new Dictionary<Box,
                                                string>(boxEqC);

            Box redBox = new Box(4, 3, 4);
            Box blueBox = new Box(4, 3, 4);

            boxes.Add(redBox, "red");
            boxes.Add(blueBox, "blue");

            Console.WriteLine(redBox.GetHashCode());
            Console.WriteLine(blueBox.GetHashCode());
        }
        catch (ArgumentException argEx) {

            Console.WriteLine(argEx.Message);
        }
    }
}

public class Box {
    public Box(int h, int l, int w) {
        this.Height = h;
        this.Length = l;
        this.Width = w;
    }
    public int Height { get; set; }
    public int Length { get; set; }
    public int Width { get; set; }
}

class BoxEqualityComparer : IEqualityComparer<Box> {

    public bool Equals(Box b1, Box b2) {
        if (b1.Height == b2.Height & b1.Length == b2.Length
                            & b1.Width == b2.Width) {
            return true;
        }
        else {
            return false;
        }
    }

    public int GetHashCode(Box bx) {
        int hCode = bx.Height ^ bx.Length ^ bx.Width;
        return hCode.GetHashCode();
    }
}

難道 Equals 方法實現不足以比較兩個 Box 對象嗎? 這就是我們告訴框架用於比較對象的規則的地方。 為什么需要 GetHashCode?

謝謝。

盧西安

首先介紹一下背景...

.NET 中的每個對象都有一個 Equals 方法和一個 GetHashCode 方法。

Equals 方法用於將一個對象與另一個對象進行比較 - 以查看兩個對象是否等效。

GetHashCode 方法生成對象的 32 位整數表示形式。 由於對一個對象可以包含多少信息沒有限制,某些散列碼由多個對象共享——因此散列碼不一定是唯一的。

字典是一種非常酷的數據結構,它以更高的內存占用為代價換取(或多或少)添加/刪除/獲取操作的恆定成本。 但是,這是迭代的糟糕選擇。 在內部,字典包含一個桶數組,其中可以存儲值。 將 Key 和 Value 添加到字典時,會在 Key 上調用 GetHashCode 方法。 返回的哈希碼用於確定應存儲鍵/值對的桶的索引。

當您要訪問 Value 時,您再次傳入 Key。 在Key上調用GetHashCode方法,定位到包含Value的bucket。

當 IEqualityComparer 傳遞到字典的構造函數時,將使用 IEqualityComparer.Equals 和 IEqualityComparer.GetHashCode 方法而不是 Key 對象上的方法。

現在要解釋為什么需要這兩種方法,請考慮以下示例:

BoxEqualityComparer boxEqC = new BoxEqualityComparer(); 

Dictionary<Box, String> boxes = new Dictionary<Box, string>(boxEqC); 

Box redBox = new Box(100, 100, 25);
Box blueBox = new Box(1000, 1000, 25);

boxes.Add(redBox, "red"); 
boxes.Add(blueBox, "blue"); 

在您的示例中使用 BoxEqualityComparer.GetHashCode 方法,這兩個框具有相同的哈希碼 - 100^100^25 = 1000^1000^25 = 25 - 即使它們顯然不是同一個對象。 在這種情況下它們是相同的哈希碼的原因是因為您使用了 ^(按位異或)運算符,因此 100^100 抵消了零,1000^1000 也是如此。 當兩個不同的對象具有相同的鍵時,我們稱之為碰撞。

當我們將兩個具有相同哈希碼的鍵/值對添加到字典中時,它們都存儲在同一個存儲桶中。 因此,當我們想要檢索一個 Value 時,會在我們的 Key 上調用 GetHashCode 方法來定位存儲桶。 由於存儲桶中有多個值,字典遍歷存儲桶中的所有鍵/值對,調用鍵上的 Equals 方法以找到正確的值。

在您發布的示例中,這兩個框是等效的,因此 Equals 方法返回 true。 在這種情況下,字典有兩個相同的鍵,因此會引發異常。

TLDR

所以綜上所述,GetHashCode 方法就是用來生成一個存放對象的地址。 所以字典不必搜索它。 它只是計算哈希碼並跳轉到該位置。 Equals 方法是一種更好的相等性測試,但不能用於將對象映射到地址空間。

GetHashCode用於字典集合,它創建哈希以在其中存儲對象。 這是一篇很好的文章,為什么以及如何使用IEqualtyComparerGetHashCode http://dotnetperls.com/iequalitycomparer

雖然Dictionary<TKey,TValue>可以讓它的GetValue和類似方法在每個存儲的鍵上調用Equals以查看它是否與正在尋找的鍵匹配,但這會非常慢。 相反,像許多基於散列的集合一樣,它依賴於GetHashCode來快速排除大多數不匹配的值。 如果對正在尋找的項目調用GetHashCode產生 42,並且一個集合有 53,917 個項目,但在其中的 53,914 個項目上調用GetHashCode產生的值不是 42,那么只需將 3 個項目與正在尋找的項目進行比較。 其他 53,914 可以安全地忽略。

GetHashCode包含在IEqualityComparer<T>是允許字典的使用者可能希望將它們視為相等的對象,而這些對象通常不會將彼此視為相等。 最常見的例子是調用者想要使用字符串作為鍵但使用不區分大小寫的比較。 為了使其有效地工作,字典需要具有某種形式的哈希函數,該函數將為“Fox”和“FOX”產生相同的值,但希望為“box”或“zebra”產生其他值。 由於String中內置的GetHashCode方法不能那樣工作,因此字典需要從其他地方獲取這樣的方法,而IEqualityComparer<T>是最合乎邏輯的地方,因為對這樣的哈希碼的需求將非常相關使用Equals方法認為“Fox”和“FOX”彼此相同,但不是“box”或“zebra”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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