使用xor的GetHashCode()问题

时间:2009-06-17 17:58:36

标签: c# .net 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()时,处理易于互换的属性值的最佳方法是什么?

  

另请参阅

     

What is the best algorithm for an overridden System.Object.GetHashCode?

7 个答案:

答案 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