-2

在接口GetHashCode方法的文档中的“实现者注释”部分中,它指出:IEqualityComparer<T>

实现需要确保如果 Equals 方法为两个对象 x 和 y 返回 true,则 GetHashCode 方法为 x 返回的值必须等于为 y 返回的值。

众所周知T,如果两个项目相等,您为什么希望两个实例返回相同的哈希码;它们不同意味着它们不相等,而它们相同则意味着它们可能相等。

当两个实例不相等时,我将返回值的引号解释为未定义(即使它们的值可能表明如此)。

以以下为例。我有一个序列int?,我想将其用于统计分类,其中每个非空值int?代表一个类的一个属性(想想枚举值)。在这些值为空的情况下,您不希望将这些值视为相等,因为它们会使训练集偏向于缺失值。如果有的话,在这种情况下,与其他空值相比,您希望空值返回 false。

问题是,在该GetHashCode方法中,当给定 null 时,我可能想要返回 0 (或其他一些数字,也许Int32.MinValue)。现在,我知道当使用此IEqualityComparer<T>实现键入任何内容时,检查字典中是否存在键的性能对于这些情况不会是最佳的。

也就是说GetHashCode,当调用Equals返回 false 时,返回一个已知与其他值冲突的值是否有效?我倾向于是的,因为上面的引用在这件事上是未定义的。

4

3 回答 3

7

几乎所有类型都有两个值是绝对必要的,这样v1v2

v1.Equals(v2) == false
v1.GetHashCode() == v2.GetHashCode()

... 或具有 . 的等价物IEqualityComparer<T>。唯一不是这种情况的情况是最多有 2 32 个不同的(不相等的)值。一旦有更多的值,鸽子洞原则就会 强制哈希码被重用——只是没有足够的哈希码来循环!

Eric Lippert 有一篇很棒的关于哈希码的博文,非常值得一读。基本上我认为你有正确的想法,但值得加强它们。

顺便说一句,空值问题是一个有趣的问题。IEqualityComparer<T>允许GetHashCode抛出异常,但我相信内置Comparer<T>实现永远不会。听起来你确实有一个问题——这Equals应该是自反的——所以空值应该等于它自己。您可能需要仔细考虑这一点……您可以表示“不同”的空值吗?

于 2011-10-05T05:34:32.663 回答
2

IMO:由于Equals始终是对象相等性的最终仲裁者,GetHashCode因此只是不相等值的捷径。在返回相同值的情况下GetHashCode(无论对象是否实际上相等),Equals将始终被调用进行比较。预计GetHashCode不相等的值之间可能会发生冲突。我没有看到任何关于这种行为的模棱两可或未定义的东西。

于 2011-10-05T04:29:21.160 回答
1

只要满足您引用的条件,您就可以返回任何您想要的值。否则,依赖此条件的类将无法正常工作。

例如,获取一个由不区分大小写的键索引的字典,并假设您的 GetHashCode 实现返回第一个字符的值。所以“A”和“a”是相等的,但具有不同的哈希值(65 和 97)。换句话说:你违反了规则。如果您随后执行以下操作:

dict["A"] = "something";
Console.WriteLine(dict["a"]);

那么即使键“A”和“a”相等,第二行也可能会因 KeyNotFoundException 而失败。

于 2011-10-05T04:53:47.697 回答