Нужно ли переопределить GetHashCode () для ссылочных типов? - PullRequest
18 голосов
/ 20 апреля 2009

Я прочитал большинство вопросов по StackOverflow относительно GetHashCode. Но я все еще не уверен, должен ли я переопределить GetHashCode для ссылочных типов. Я взял следующее из чьего-то ответа в другом вопросе:

Object.GetHashCode () использует внутренний поле в классе System.Object для генерировать значение хеша. Каждый объект создан присваивается уникальный объект ключ, хранится как целое число, когда это создано. Эти ключи начинаются с 1 и увеличивать каждый раз, когда новый объект любой тип создается.

Если это все еще верно в .NET Framework 3.5 (может кто-нибудь подтвердить это?), То единственная проблема, с которой я сталкиваюсь при реализации ссылочных типов по умолчанию, состоит в том, что хеш-код будет иметь плохое распространение.

Я разобью мои вопросы:

a) Так что рекомендуется переопределить GetHashCode, если он используется в Dictionary или реализация по умолчанию работает нормально?

b) У меня есть ссылочные типы, где это было бы легко сделать, поскольку у них есть поля, которые уникально идентифицируют их, но как насчет тех ссылочных типов, где все члены также являются ссылочными типами. Что мне там делать?

Ответы [ 3 ]

16 голосов
/ 20 апреля 2009

Вам нужно переопределить GetHashCode () только для ссылочных типов, если вы переопределите Object.Equals ().

Причина этого проста - обычно 2 ссылки всегда будут разными (a.Equals (b) == false, если только они не являются одним и тем же объектом). Реализация по умолчанию GetHashCode () предоставит 2 различных хеша в этом случае, так что все хорошо.

Если вы переопределите Equals (), то это поведение не гарантируется. Если два объекта равны (согласно Equals ()), вам нужно гарантировать, что они будут иметь одинаковый хеш-код с GetHashCode, поэтому вы должны переопределить его.

0 голосов
/ 11 июля 2009

Посмотрите на комментарий, который я оставил к статье: Метод расширения GetHashCode

0 голосов
/ 20 апреля 2009

Я только что сделал пример теста, и я не вижу, как он начинается с 1 и получает приращение.

for (int i = 0; i < 16; i++)
{
    object obj = new object();
    Console.Write(obj.GetHashCode() + " ");
}

с этими результатами:

45653674 41149443 39785641 45523402 35287174 44419000 52697953 22597652 
10261382 59109011 42659827 40644060 17043416 28756230 18961937 47980820

На самом деле, используя Reflector, я мог видеть только это:

internal static extern int InternalGetHashCode(object obj);

Итак, как это на самом деле происходит, для меня загадка (может быть, есть образец, но я не собираюсь копать глубже в этом месте - может быть, какое-то «псевдослучайное число» алгоритм ? ). Кто-нибудь из команды CLR может ответить на этот вопрос.

Что касается других вопросов, Рид на самом деле избил меня ударом: GetHashCode и Equals. MSDN page описывает это с несколькими подробностями, на всякий случай.

...