IEqualityComparer <t> GetHashCode在项目不相等时返回相同的值?</t>

时间:2011-10-05 04:24:34

标签: .net gethashcode iequalitycomparer

GetHashCode methodIEqualityComparer<T> interface文档的“实施者注意事项”部分中,它指出:

  

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

众所周知,为什么你希望两个T实例在两个项相等的情况下返回相同的哈希码;它们不同意味着它们不相等,而它们是相同的意味着它们可能相等。

当两个实例相等时,我将引用解释为未定义的返回值(即使它们的值可能是这样的)。

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

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

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

3 个答案:

答案 0 :(得分:7)

几乎所有类型绝对必要,因为有两个值v1v2

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

...或等同于IEqualityComparer<T>。唯一的情况是不是的情况下,最多有2个 32 不同(不相等)的值。只要有更多的值,pigeon-hole principle 强制哈希码就可以重复使用 - 只有没有足够的哈希码可以循环使用!

Eric Lippert有一个great blog post on hash codes非常值得一读。基本上我认为你有正确的想法,但值得加强它们。

顺便说一下,nulls的问题很有意思。 IEqualityComparer<T>允许GetHashCode抛出异常,但我相信内置的Comparer<T>实现永远不会。听起来你确实遇到了一个问题 - Equals应该是自反的 - 所以空值应该等于它自己。你可能需要仔细考虑那个......你能代表“不同的”空值吗?

答案 1 :(得分:2)

IMO:由于Equals始终是对象相等的最终仲裁者,GetHashCode只是非等值的捷径。如果从GetHashCode返回相同的值(无论对象实际上是否相等),则始终会调用Equals进行比较。预计GetHashCode可能会在不相等的值之间发生冲突。关于这种行为,我没有看到任何含糊不清或不明确的内容。

答案 2 :(得分:1)

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

例如,取一个由不区分大小写的键索引的字典,并说GetHashCode的实现返回第一个字符的值。所以“A”和“a”相等但具有不同的散列值(65和97)。换句话说:你违反了规则。如果你那么做:

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

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