我的理解是,您通常应该使用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,那么我们就有了相等
问题在于:
Foo one = new Foo(1, 2);
Foo two = new Foo(2, 1);
if (one.Equals(two)) { ... } // This is true!
这两个都为GetHashCode()生成值3,导致Equals()返回true。显然,这是一个简单的例子,只有两个属性,我可以简单地比较Equals()方法中的各个属性。但是,如果课程更复杂,这将很快失控。
我知道有时候只设置一次哈希码是很有意义的,并且总是返回相同的值。但是,对于需要对平等进行评估的可变对象,我认为这不合理。
在实现GetHashCode()时,处理易于互换的属性值的最佳方法是什么?
另请参阅
What is the best algorithm for an overridden System.Object.GetHashCode?
答案 0 :(得分:27)
首先关闭 - 不要仅仅根据GetHashCode()实现Equals() - 即使对象不相等,哈希码有时也会发生碰撞。
GetHashCode()的合同包括以下内容:
Andrew Hare建议我加入他的答案:
我建议您阅读this solution(顺便提一下我们自己的Jon Skeet),以便“更好”地计算哈希码。
不,以上相对较慢而且 没有多大帮助。有人用 异或(例如a ^ b ^ c)但我更喜欢 Josh Bloch所展示的一种方法 “有效的Java”:
public override int GetHashCode() { int hash = 23; hash = hash*37 + craneCounterweightID; hash = hash*37 + trailerID; hash = hash*37 + craneConfigurationTypeCode.GetHashCode(); return hash; }
23和37是任意数字 这是共同主要的。
上述优于XOR的好处 方法是,如果你有一个类型 它有两个值 经常是相同的,对那些进行异或 值总是给出相同的 结果(0)而上述将 区分它们,除非 你很不走运。
如上面的代码段所述,您可能还需要查看包含对主题的良好处理的Joshua Bloch's book, Effective Java,(哈希码讨论也适用于.NET)。
答案 1 :(得分:2)
Andrew已经发布了一个生成更好的哈希代码的好例子,但是请记住,不应该使用哈希码作为相等检查,因为它们不能保证是唯一的。
这是一个简单的例子,说明为什么这是一个双重对象。它具有比int更多的可能值,因此不可能为每个double赋予唯一的int。哈希实际上只是第一遍,当你需要快速找到密钥时,在字典等情况下使用,首先比较哈希,可以排除大部分可能的密钥,只有匹配哈希的密钥需要有费用完全相等检查(或其他collision resolution方法)。
答案 2 :(得分:1)
散列总是涉及冲突,你必须处理它(例如,比较散列值,如果它们相等,则完全比较类中的值以确保类相等)。
使用简单的XOR,你会遇到很多碰撞。如果你想要更少,可以使用一些数学函数,在不同的位上分配值(位移,乘以质数等)。
答案 3 :(得分:1)
阅读Overriding GetHashCode for mutable objects? C#并考虑实施IEquatable<T>
答案 4 :(得分:1)
快速生成并良好分配哈希
public override int GetHashCode()
{
return A.GetHashCode() ^ B.GetHashCode(); // XOR
}
答案 5 :(得分:0)
由于好奇心,因为哈希码通常是一个比较糟糕的想法,所以只是做下面的代码不是更好,或者我错过了什么?
public override bool Equals(object obj)
{
bool isEqual = false;
Foo otherFoo = obj as Foo;
if (otherFoo != null)
{
isEqual = (this.A == otherFoo.A) && (this.B == otherFoo.B);
}
return isEqual;
}
答案 6 :(得分:0)
有几种更好的哈希实现。例如FNV hash。