.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位整数表示形式。 由于对象可以包含多少信息没有限制,某些哈希码由多个对象共享 - 所以哈希码不一定是唯一的。
字典是一种非常酷的数据结构,可以换取更高的内存占用量,以换取(或多或少)增加/删除/获取操作的不变成本。 这对迭代来说是一个糟糕的选择。 在内部,一个字典包含一个可以存储值的桶数组。 将一个Key和Value添加到字典时,将在该Key上调用GetHashCode方法。 返回的散列码用于确定应存储键/值对的桶的索引。
当你想访问Value时,你再次传入Key。 在Key上调用GetHashCode方法,并找到包含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也是如此。 当两个不同的对象具有相同的键时,我们称之为碰撞。
当我们将两个具有相同散列码的键/值对添加到字典中时,它们都存储在同一个存储桶中。 所以当我们想要检索一个Value时,GetHashCode方法在我们的Key上被调用来定位这个bucket。 由于存储桶中存在多个值,因此字典会遍历桶中的所有键/值对,从而调用Keys上的Equals方法来查找正确的值。
在你发布的例子中,这两个框是等价的,所以Equals方法返回true。 在这种情况下,字典有两个相同的键,所以它会抛出一个异常。
TLDR
总而言之,GetHashCode方法用于生成存储对象的地址。 所以字典不必搜索它。 它只是计算哈希码并跳转到那个位置。 Equals方法是对等式的更好测试,但不能用于将对象映射到地址空间。
希望有所帮助
GetHashCode用于字典库,它创建用于存储对象的散列。 这里有一篇不错的文章,为什么以及如何使用IEqualtyComparer和GetHashCode http://dotnetperls.com/iequalitycomparer
虽然Dictionary<TKey,TValue>
有可能使其GetValue
和类似的方法在每个存储的关键字上调用Equals
,以查看它是否与正在搜索的关键字相匹配,但这会非常缓慢。 相反,像很多基于哈希的集合一样,它依赖于GetHashCode
来快速排除大多数不匹配的值。 如果在调用GetHashCode
正在寻求一个项目产量42,收藏有53917项,但调用GetHashCode
上的项目53914产量比42以外的值,则只有3个项目将不得不寻求与以进行比较。 其他53,914可以安全地被忽略。
GetHashCode
包含在IEqualityComparer<T>
是为了允许字典的消费者可能希望将其视为通常不会相互对等的相同对象。 最常见的例子是一个调用者想要使用字符串作为键,但使用不区分大小写的比较。 为了有效地完成这项工作,字典需要具有某种形式的散列函数,它将为“Fox”和“FOX”产生相同的值,但希望为“box”或“zebra”产生其他值。 由于内置于String
中的GetHashCode
方法不能以这种方式工作,因此字典需要从别的地方获得这样的方法,并且IEqualityComparer<T>
是最合乎逻辑的地方,因为对这样的哈希代码的需求会非常强烈地关联用Equals
方法考虑“Fox”和“FOX”彼此相同,但不包括“box”或“zebra”。
上一篇: What's the role of GetHashCode in the IEqualityComparer<T> in .NET?
下一篇: why do i need GetHashcode() in the IEqualityComparer interface?