Подтвердить что ты не робот

Нужно ли переопределять GetHashCode() для ссылочных типов?

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

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

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

Я сломаю свои вопросы:

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Я просто выполнил тестовый тест, и я не вижу, как он начинается с 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 описывает это с несколькими подробностями gory на всякий случай.