Какова правильная реализация для GetHashCode () для классов сущностей? - PullRequest
15 голосов
/ 03 февраля 2009

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

Все классы сущностей имеют свойство Id, которое может иметь значение null. (Это первичный ключ любой таблицы, которой соответствует класс сущности.)

public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
                return false;

            if (base.Equals(obj))
                return true;

            return Id.HasValue && ((EntityBase) obj).Id.HasValue &&
                   Id.Value == ((EntityBase) obj).Id.Value;
        }

Учитывая эту реализацию Equals (), как правильно реализовать GetHashCode ()?

Ответы [ 4 ]

23 голосов
/ 03 февраля 2009

Если вы производите от чего-то, что уже переопределяет GetHashCode, я бы реализовал это как:

public override int GetHashCode()
{
    unchecked
    {
        int hash = 37;
        hash = hash * 23 + base.GetHashCode();
        hash = hash * 23 + Id.GetHashCode();
        return hash;
    }
}

Нулевое значение Id вернет 0 для Id.GetHashCode ().

Если ваш класс просто наследуется от Object, я бы просто возвратил Id.GetHashCode() - вы не хотите включить реализацию object.GetHashCode в ваш хэш-код, поскольку в итоге это становится идентичностью объекта .

Обратите внимание, что ваше определение равенства не будет возвращать true, если ни один из объектов не имеет идентификатора, но один и тот же хеш-код будет возвращен из обоих объектов. Вы можете рассмотреть возможность изменения реализации Equals.

2 голосов
/ 13 декабря 2011

А как насчет использования типа как части хеш-кода?
Это будет хорошая реализация?

public class Foo
{
    public int Id { get; set; }

    // other properties here
    // ......

    public override int GetHashCode()
    {
        int hash = 37;
        hash = hash * 23 + typeof(Foo).GetHashCode();
        hash = hash * 23 + Id.GetHashCode();
        return hash;
    }
}
2 голосов
/ 24 октября 2009

Ответ Джона Скита - хорошее решение, однако вы можете добавить непроверенный блок кода, чтобы разрешить переполнение целых чисел

unchecked
{
  int hash = ...;
  return hash
}

https://msdn.microsoft.com/en-us/library/khy08726(v=vs.140).aspx

Если не указано ни отмечено, ни отмечено, контекст по умолчанию зависит от внешних факторов, таких как параметры компилятора.

Я также хотел бы добавить, что использование base.GetHashCode() в POCO вызовет значение по умолчанию object.GetHashCode. Это определенно не то, что вы хотите ...

1 голос
/ 03 февраля 2009

Правильно реализовать GetHashCode() можно только в том случае, если свойство Id является неизменным на протяжении всего времени существования экземпляра (или, по крайней мере, на время, когда необходимо использовать его хэш, например, когда объект находится на карте или другая коллекция, требующая хеширования).

Предполагая, что это так, вы можете просто использовать значение Id в качестве хэша для всех допустимых значений, а затем использовать фиксированный хэш для нуля. Я не могу вспомнить, что является наиболее подходящим для этого, но я бы предположил, что случайно выбранное значение для нуля (случайно выбранное до компиляции, а не во время выполнения) или медианное значение действительных Id значений (т.е. на полпути между 0 и int.Max).

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