开发者

Creating 'good' hash codes for .NET ala Boost.Functional/Hash

开发者 https://www.devze.com 2023-03-14 03:44 出处:网络
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 ask

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开发者_C百科 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.


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


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.


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).


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


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

0

精彩评论

暂无评论...
验证码 换一张
取 消