Троелсен в своей книге, советует переопределить метод ToString()
у класса(переопределенная версия возвращает строку из полей всего класса через пробел), а потом в методе GetHashCode
вызывать this.ToString().GetHashCode()
.
Где-то читал критику такой реализации, например, вызов ToString() будет порождать мусор.
Правда ли, что она не очень хороша.
Какие могут быть альтернативы?
Проблема со строкой состоит в том, что GetHashCode()
может вызываться очень часто, много тысяч раз в секунду. Например, при поиске элемента в HashSet<T>
или поиске ключа в Dictionary<K, V>
у каждого искомого элемента берётся хэшкод. Если при этом будет каждый раз создаваться временная, никому за пределами метода не нужная строка, их потом должен будет очистить сборщик мусора.
Поэтому функция GetHashCode
должна быть по возможности быстрой и не создавать дополнительных объектов.
По поводу того, как же лучше считать хэшкод, я бы посоветовал немного переделанный код из ответа @Umed:
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + field1.GetHashCode(); // для поля типа-значения, например int
hash = hash * 23 + field2.GetHashCode(); // то же самое
if (field3 != null) // а это для поля ссылочного типа
hash = hash * 23 + field3.GetHashCode();
return hash;
}
}
Вместо 17 и 23 можно взять другие разные простые числа.
Ещё по теме: Почему при переопределении Equals советуют также переопределять GetHashCode.
Как вариант, можно посчитать его как сумму хэшей его полей:
public override int GetHashCode()
{
int result;
uncheked
{
// если поле ссылочного типа,
// то необходима проверка на null
// если field1 будет null, то подставится 0
result = this.field1?.GetHashCode() ?? 0;
result += this.field2?.GetHashCode() ?? 0;
//...
result += this.fieldN.GetHashCode();
}
return result;
}
Либо через создание анонимного класса (подсмотрел в английской SO):
public override int GetHashCode()
{
return new { this.field1, this.field2, /*... ,*/ this.fieldN }.GetHashCode();
}
Такой вариант тоже работает достаточно быстро, но за тем исключением, что каждый вызов порождает анонимный класс.
Там же можно посмотреть ответ Джона Скита. Он накидал алгоритм с выбором двух случайных констант (они не меняются, случайных - потому что Вам надо их придумать один раз) и подсчёта хэша следующим образом:
public override int GetHashCode()
{
unchecked
{
int hash = 17;
// если поле ссылочного типа,
// то необходима проверка на null
hash = hash * 23 + field1?.GetHashCode() ?? 0;
// если это, например, int, то проверка ни к чему
hash = hash * 23 + field3.GetHashCode();
return hash;
}
}
Добавил от себя проверку на null, о которой он там пишет в ответе
Советую перейти по ссылке и посмотреть, там много полезного написано.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Допустим, имеется объект с переопределенным GetHashCode, который я хочу сделать ключемGetHashCode вычисляется, как совокупность GetHashCode всех полей
Доброго времени суток, сейчас нахожусь в поисках IMAP клиента, который бы поддерживал работу через прокси и был бесплатнымГугл достаточно...
Хочу поставить условный breakpoint, который сработает, если программа съела слишком много памятиПопытался прописать такое в условие: