4

For C++ I've always been using Boost.Functional/Hash to create good hash values without having to deal with bit shifts, XORs and prime numbers. Is there any libraries that produces good (I'm not asking for optimal) hash values for C#/.NET? I would use this utility to implement GetHashCode(), not cryptographic hashes.

To clarify why I think this is useful, here's the implementation of boost::hash_combine which combines to hash values (ofcourse a very common operation when implementing GetHashCode()):

seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);

Clearly, this sort of code doesn't belong in the implementation of GetHashCode() and should therefor be implemented elsewhere.

larsmoa
  • 12,604
  • 8
  • 62
  • 85
  • 1
    How do you define good hashes? For what purpose? And why don't you like `GetHashCode()`? – CodesInChaos Jun 21 '11 at 09:06
  • I think you are misunderstanding the OP. He wants to have something like Boost.Functional/Hash *to use it inside `GetHashCode`*! – Daniel Hilgarth Jun 21 '11 at 09:17
  • 1
    Related: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode – CodesInChaos Jun 21 '11 at 09:41
  • @CodeInChaos: I like GetHashCode(), I just want a better way to implement it. Most developers end up just doing `_member1.GetHashCode() + _member2.GetHashCode()` etc. – larsmoa Jun 21 '11 at 10:05
  • "Clearly, this sort of code doesn't belong in the implementation of `GetHashCode()`": I don't see any reason why not unless you are writing a lot of such merges then move to a helper function. – Richard Jun 21 '11 at 10:15

5 Answers5

4

I wouldn't used a separate library just for that. As mentioned before, for the GetHashCode method it is essential to be fast and stable. Usually I prefer to write inline implementation, but it might be actually a good idea to use a helper class:

internal static class HashHelper
{
    private static int InitialHash = 17; // Prime number
    private static int Multiplier = 23; // Different prime number

    public static Int32 GetHashCode(params object[] values)
    {
        unchecked // overflow is fine
        {
            int hash = InitialHash;

            if (values != null)
                for (int i = 0; i < values.Length; i++)
                {
                    object currentValue = values[i];
                    hash = hash * Multiplier
                        + (currentValue != null ? currentValue.GetHashCode() : 0);
                }

            return hash;
        }
    }
}

This way common hash-calculation logic can be used:

public override int GetHashCode()
{
    return HashHelper.GetHashCode(field1, field2);
}
Regent
  • 5,502
  • 3
  • 33
  • 59
2

The answers to this question contains some examples of helper-classes that resembles Boost.Functional/Hash. None looks quite as elegant, though.

I am not aware of any real .NET library that provides the equivalent.

Community
  • 1
  • 1
Rasmus Faber
  • 48,631
  • 24
  • 141
  • 189
1

Unless you have very specific requirements you don't need to calculate your type's hashcode from first principles. Rather combine the hash codes of the fields/properties you use for equality determination in one of the simple ways, something like:

int hash = field1.GetHashCode();
hash = (hash *37) + field2.GetHashCode();

(Combination function taken from §3.3.2 C# in Depth, 2nd Ed, Jon Skeet).

Richard
  • 106,783
  • 21
  • 203
  • 265
  • 1
    Use 31 not 37. 37 can lead to degenerate hashes because Dictionary sometimes chooses it as the capacity. – CodesInChaos Jun 21 '11 at 09:39
  • 2
    @CodeInChaose: I suspect that *any* value will have degenerate cases when the whole system is considered. Feel free to pick better values – in a general purpose answer they are essentially arbitrary. – Richard Jun 21 '11 at 10:09
0

To avoid the boxing issue chain your calls using a generic extension method on Int32

public static class HashHelper
{
    public static int InitialHash = 17; // Prime number
    private static int Multiplier = 23; // Different prime number

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Int32 GetHashCode<T>( this Int32 source, T next )
    {
        // comparing null of value objects is ok. See
        // http://stackoverflow.com/questions/1972262/c-sharp-okay-with-comparing-value-types-to-null
        if ( next == null )
        {
            return source;
        }
        unchecked
        {
            return source + next.GetHashCode();
        }
    }

}

then you can do

HashHelper
    .InitialHash
    .GetHashCode(field0)
    .GetHashCode(field1)
    .GetHashCode(field2);
bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
-3

Have a look at this link, it describes MD5 hashing. Otherwise use GetHashCode().

Bibhu
  • 4,053
  • 4
  • 33
  • 63
  • OP isn't talking about cryptographic hashes, more like hash functions as used by `GetHashCode` etc. http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx – LukeH Jun 21 '11 at 09:26
  • @Richard & @LukeH - please read the question carefully he does not wants a optimal solution but a good one. – Bibhu Jun 21 '11 at 10:01
  • 1
    Check the updated question: this is a question about the implementation of `GetHashCode`. – Richard Jun 21 '11 at 10:16