我的理解是你通常应该使用xor和GetHashCode()生成一个int来通过它的值来识别你的数据(而不是通过它的引用) . 这是一个简单的例子:
class Foo
{
int m_a;
int m_b;
public int A
{
get { return m_a; }
set { m_a = value; }
}
public int B
{
get { return m_b; }
set { m_b = value; }
}
public Foo(int a, int b)
{
m_a = a;
m_b = b;
}
public override int GetHashCode()
{
return A ^ B;
}
public override bool Equals(object obj)
{
return this.GetHashCode() == obj.GetHashCode();
}
}
我的想法是,我想根据属性A和B的值将Foo的一个实例与另一个实例进行比较 . 如果Foo1.A == Foo2.A和Foo1.B == Foo2.B,那么我们就有了相等性 .
Here's the problem:
Foo one = new Foo(1, 2);
Foo two = new Foo(2, 1);
if (one.Equals(two)) { ... } // This is true!
这些都为GetHashCode()生成值3,导致Equals()返回true . 显然,这是一个简单的例子,只有两个属性,我可以简单地比较Equals()方法中的各个属性 . 然而,对于更复杂的类,这将很快失控 .
我知道有时候只设置一次哈希码是很有意义的,并且总是返回相同的值 . 但是,对于需要对平等进行评估的可变对象,我认为这不合理 .
What's the best way to handle property values that could easily be interchanged when implementing GetHashCode()?
另请参阅重写的System.Object.GetHashCode的最佳算法是什么?
7 回答
首先 - 不要仅在GetHashCode()方面实现Equals() - 即使对象不相等,哈希码有时也会发生冲突 .
GetHashCode()的 Contract 包括以下内容:
不同的哈希码意味着对象绝对不相等
相同的哈希码意味着对象可能相等(但可能不是)
Andrew Hare建议我加入他的答案:
我建议您阅读this solution(通过我们自己的Jon Skeet,顺便说一下)"better"方式来计算哈希码 .
如上面的代码片段所述,您可能还需要查看Joshua Bloch's book, Effective Java,,其中包含对主题的良好处理(哈希码讨论也适用于.NET) .
Andrew已经发布了一个生成更好的哈希代码的好例子,但是请记住,不应该使用哈希码作为相等检查,因为它们不能保证是唯一的 .
对于一个简单的例子,为什么这是一个双重对象 . 它具有比int更多的可能值,因此不可能为每个double赋予唯一的int . 哈希实际上只是第一遍,当你需要快速找到密钥时用于字典之类的情况,首先比较哈希可以排除大部分可能的密钥,只有匹配哈希的密钥需要有费用完全相等检查(或其他collision resolution方法) .
散列总是涉及冲突,你必须处理它(例如,比较散列值,如果它们相等,则完全比较类中的值以确保类相等) .
使用简单的XOR,您将获得许多碰撞 . 如果你想要更少,可以使用一些数学函数,在不同的位上分配值(位移,乘以素数等) .
阅读Overriding GetHashCode for mutable objects? C#并考虑实施
IEquatable<T>
快速生成和良好的散列分布
出于好奇,因为哈希码通常是一个糟糕的比较想法,只是做下面的代码不是更好,或者我错过了什么?
有几种更好的哈希实现 . FNV hash例如 .