GetHashCode() problem using xor

旧城冷巷雨未停 提交于 2019-12-03 12:35:50
Michael Burr

First off - Do not implement Equals() only in terms of GetHashCode() - hashcodes will sometimes collide even when objects are not equal.

The contract for GetHashCode() includes the following:

  • different hashcodes means that objects are definitely not equal
  • same hashcodes means objects might be equal (but possibly might not)

Andrew Hare suggested I incorporate his answer:

I would recommend that you read this solution (by our very own Jon Skeet, by the way) for a "better" way to calculate a hashcode.

No, the above is relatively slow and doesn't help a lot. Some people use XOR (eg a ^ b ^ c) but I prefer the kind of method shown in Josh Bloch's "Effective Java":

public override int GetHashCode()
{
    int hash = 23;
    hash = hash*37 + craneCounterweightID;
    hash = hash*37 + trailerID;
    hash = hash*37 + craneConfigurationTypeCode.GetHashCode();
    return hash;
}

The 23 and 37 are arbitrary numbers which are co-prime.

The benefit of the above over the XOR method is that if you have a type which has two values which are frequently the same, XORing those values will always give the same result (0) whereas the above will differentiate between them unless you're very unlucky.

As mentioned in the above snippet, you might also want to look at Joshua Bloch's book, Effective Java, which contains a nice treatment of the subject (the hashcode discussion applies to .NET as well).

Andrew has posted a good example for generating a better hash code, but also bear in mind that you shouldn't use hash codes as an equality check, since they are not guaranteed to be unique.

For a trivial example of why this is consider a double object. It has more possible values than an int so it is impossible to have a unique int for each double. Hashes are really just a first pass, used in situations like a dictionary when you need to find the key quickly, by first comparing hashes a large percentage of the possible keys can be ruled out and only the keys with matching hashes need to have the expense of a full equality check (or other collision resolution methods).

Hashing always involves collisions and you have to deal with it (f.e., compare hash values and if they are equal, exactly compare the values inside the classes to be sure the classes are equal).

Using a simple XOR, you'll get many collisions. If you want less, use some mathematical functions that distribute values across different bits (bit shifts, multiplying with primes etc.).

jitter

Read Overriding GetHashCode for mutable objects? C# and think about implementing IEquatable<T>

A quick generate and good distribution of hash

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

Out of curiosity since hashcodes are typically a bad idea for comparison, wouldn't it be better to just do the following code, or am I missing something?

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

There are several better hash implementations. FNV hash for example.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!