使用xor的GetHashCode()问题

我的理解是你通常应该使用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()时,处理可以轻易互换的属性值的最佳方法是什么?

也可以看看

覆盖System.Object.GetHashCode的最佳算法是什么?

首先 – 不要仅在GetHashCode()方面实现Equals() – 即使对象不相等,哈希码有时也会发生冲突。

GetHashCode()的合同包括以下内容:

  • 不同的哈希码意味着对象绝对不相等
  • 相同的哈希码意味着对象可能相等(但可能不是)

Andrew Hare建议我加入他的答案:

我建议你阅读这个解决方案 (通过我们自己的Jon Skeet ,顺便说一句),以“更好”的方式来计算哈希码。

不,以上相对较慢,并没有多大帮助。 有些人使用XOR(例如a ^ b ^ c),但我更喜欢Josh Bloch的“Effective 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的书“Effective Java”,其中包含对该主题的一种很好的处理(哈希码讨论也适用于.NET)。

Andrew已经发布了一个生成更好的哈希代码的好例子,但是请记住,不应该使用哈希码作为相等检查,因为它们不能保证是唯一的。

对于一个简单的例子,为什么这是一个双重对象。 它具有比int更多的可能值,因此不可能为每个double赋予唯一的int。 哈希实际上只是第一遍,当你需要快速找到密钥时,在字典等情况下使用,首先比较哈希,可以排除大部分可能的密钥,只有匹配哈希的密钥需要有费用完全相等检查(或其他冲突解决方法)。

散列总是涉及冲突,你必须处理它(fe,比较散列值,如果它们相等,则完全比较类中的值以确保类相等)。

使用简单的XOR,您将获得许多碰撞。 如果你想要更少,可以使用一些数学函数,在不同的位上分配值(位移,乘以素数等)。

读取覆盖可变对象的GetHashCode? C#并考虑实现IEquatable

快速生成和良好的哈希分布

 public override int GetHashCode() { return A.GetHashCode() ^ B.GetHashCode(); // XOR } 

出于好奇,因为哈希码通常是一个比较坏的想法,只是做下面的代码不是更好,或者我错过了什么?

 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; } 

有几种更好的哈希实现。 例如FNV哈希 。