C # HashCode Builder - PullRequest
       30

C # HashCode Builder

6 голосов
/ 26 мая 2010

Я часто использовал конструктор хеш-кода apache

Существует ли это для C #

Ответы [ 3 ]

3 голосов
/ 17 мая 2012

Это мой самодельный строитель.

Использование:

hash = new HashCodeBuilder().
             Add(a).
             Add(b).
             Add(c).
             Add(d).
             GetHashCode();

Не имеет значения, какие поля типа a, b, c и d, легко расширяются, нет необходимости создавать массив.

Источник:

public sealed class HashCodeBuilder
{
    private int hash = 17;

    public HashCodeBuilder Add(int value)
    {
        unchecked
        {
            hash = hash * 31 + value; //see Effective Java for reasoning
             // can be any prime but hash * 31 can be opimised by VM to hash << 5 - hash
        }
        return this;
    }

    public HashCodeBuilder Add(object value)
    {
        return Add(value != null ? value.GetHashCode() : 0);
    }

    public HashCodeBuilder Add(float value)
    {
        return Add(value.GetHashCode());
    }

    public HashCodeBuilder Add(double value)
    {
        return Add(value.GetHashCode());
    }

    public override int GetHashCode()
    {
        return hash;
    }
}

Пример использования:

public sealed class Point
{
    private readonly int _x;
    private readonly int _y;
    private readonly int _hash;

    public Point(int x, int y)
    {
        _x = x;
        _y = y;
        _hash = new HashCodeBuilder().
            Add(_x).
            Add(_y).
            GetHashCode();
    }

    public int X
    {
        get { return _x; }
    }

    public int Y
    {
        get { return _y; }
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Point);
    }

    public bool Equals(Point other)
    {
        if (other == null) return false;
        return (other._x == _x) && (other._y == _y);
    }

    public override int GetHashCode()
    {
        return _hash;
    }
}
3 голосов
/ 26 мая 2010

Я использую следующее:

public static int ComputeHashFrom(params object[] obj) {
    ulong res = 0;
    for(uint i=0;i<obj.Length;i++) {
        object val = obj[i];
        res += val == null ? i : (ulong)val.GetHashCode() * (1 + 2 * i);
    }
    return (int)(uint)(res ^ (res >> 32));
}

Использование такого помощника является быстрым, легким и надежным, но у него есть потенциальные два недостатка (с которыми вы вряд ли столкнетесь часто, но о них стоит знать):

  • Может генерировать плохие хеш-коды для некоторых распределений параметров. Например, для любых int x, ComputeHashFrom(x*-3, x) == 0 - поэтому, если у ваших объектов есть определенные патологические свойства, вы можете получить много коллизий хеш-кода, что приведет к неэффективной работе словарей и HashSets. Это вряд ли произойдет, но вычисление хеш-кода с учетом типов может легче избежать таких проблем.
  • Вычисление хеш-кода медленнее, чем могло бы быть специализированное вычисление. В частности, это включало выделение массива params и цикла - что немало ненужных накладных расходов, если вам нужно обработать только два члена.

Ни один из недостатков не вызывает каких-либо ошибок, просто неэффективность; и оба с отображением в профилировщике в виде всплесков либо в этом методе, либо во внутренних элементах потребителя хеш-кода.

2 голосов
/ 27 июня 2011

C # не имеет встроенного компоновщика HashCode, но вы можете свернуть свой собственный.Недавно у меня возникла точная проблема, и я создал этот генератор хеш-кода, который не использует бокс, используя дженерики и реализует модифицированный алгоритм FNV для генерации конкретного хэша.Но вы можете использовать любой алгоритм, какой захотите, например, один из них в System.Security.Cryptography.

    public static int GetHashCode<T>(params T[] args)
    {
        return args.GetArrayHashCode();
    }

    public static int GetArrayHashCode<T>(this T[] objects)
    {
        int[] data = new int[objects.Length];

        for (int i = 0; i < objects.Length; i++)
        {
            T obj = objects[i];
            data[i] = obj == null ? 1 : obj.GetHashCode();
        }

        return GetFnvHash(data);
    }

    private static int GetFnvHash(int[] data)
    {
        unchecked
        {
            const int p = 16777619;
            long hash = 2166136261;

            for (int i = 0; i < data.Length; i++)
            {
                hash = (hash ^ data[i]) * p;
            }

            hash += hash << 13;
            hash ^= hash >> 7;
            hash += hash << 3;
            hash ^= hash >> 17;
            hash += hash << 5;

            return (int)hash;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...