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

我想了解接口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位整数表示forms。 由于对象可以包含多less信息没有限制,因此某些哈希码由多个对象共享 – 所以哈希码不一定是唯一的。

一个字典是一个非常酷的数据结构,为了添加/删除/获取操作的(固定成本)交换更高的内存空间。 这是迭代,但不好的select。 在内部,一个字典包含一个桶数组,其中可以存储值。 将一个Key和Value添加到字典时,将在该Key上调用GetHashCode方法。 返回的散列码用于确定应存储键/值对的桶的索引。

当你想访问Value时,你再次通过Key。 在Key上调用GetHashCode方法,并find包含Value的存储桶。

将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。 当两个不同的对象具有相同的键时,我们称之为碰撞。

当我们将两个具有相同散列码的键/值对添加到字典中时,它们都存储在同一个存储桶中。 所以当我们想要检索一个值时,GetHashCode方法在我们的Key上被调用来定位这个bucket。 由于桶中有多个值,因此字典会遍历桶中的所有键/值对,调用Keys上的Equals方法来find正确的值。

在你发布的例子中,这两个框是等价的,所以Equals方法返回true。 在这种情况下,字典有两个相同的键,所以它会抛出一个exception。

TLDR

所以总而言之,GetHashCode方法用于生成存储对象的地址。 所以字典不必search它。 它只是计算哈希码并跳转到那个位置。 Equals方法是一个更好的等式testing,但不能用于将对象映射到地址空间。

希望有所帮助

GetHashCode用于字典库,它创build用于存储对象的散列。 这里是一个不错的文章为什么以及如何使用IEqualtyComparerGetHashCode http://dotnetperls.com/iequalitycomparer

虽然Dictionary<TKey,TValue>有可能使其GetValue和类似的方法在每一个存储的关键字上调用Equals ,以查看它是否与正在寻找的关键字相匹配,这将会非常缓慢。 相反,像很多基于哈希的集合,它依赖于GetHashCode来快速排除大多数不匹配的值。 如果对被查找的项目调用GetHashCode产生42,并且一个集合有53,917个项目,但是在53,914项目上调用GetHashCode产生的值不是42,那么只有3个项目必须与正在search的项目进行比较。 其他53,914可以安全地被忽略。

一个GetHashCode被包含在一个IEqualityComparer<T>是为了允许字典的消费者可能希望被视为平等的对象,通常不会相互对等。 最常见的例子是一个调用者想要使用string作为键,但使用不区分大小写的比较。 为了有效地工作,字典需要有一些forms的散列函数,它们会产生“狐狸”和“狐狸”相同的值,但是希望为“盒子”或“斑马”产生别的东西。 由于内置到String中的GetHashCode方法不能以这种方式工作,字典将需要从其他地方获得这样的方法,并且IEqualityComparer<T>是最合乎逻辑的地方,因为对这样的哈希代码的需求将会非常强烈地关联用Equals方法,认为“Fox”和“FOX”彼此相同,而不是“box”或“zebra”。