在GetHashCode
method的IEqualityComparer<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时,返回已知与其他值冲突的值是否有效?我倾向于是,因为上面的引用在这个问题上是不确定的。
答案 0 :(得分:7)
几乎所有类型绝对必要,因为有两个值v1
和v2
,
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”相等。