Нужно ли переопределять GetHashCode() для ссылочных типов?
Я прочитал большинство вопросов о StackOverflow относительно GetHashCode
. Но я до сих пор не уверен, нужно ли переопределять GetHashCode
для ссылочных типов. Я подобрал следующее от кого-то, отвечающего в другом вопросе:
Object.GetHashCode() использует внутренний в классе System.Object для генерировать хеш-значение. Каждый объект создан присваивается уникальный объект ключ, сохраняемый как целое число, когда он создано. Эти ключи начинаются с 1 и прирост каждый раз, когда новый объект создается любой тип.
Если это все еще верно в .NET Framework 3.5 (может кто-то, пожалуйста, подтвердите?), то единственная проблема, с которой я сталкиваюсь со стандартными реализациями ссылочных типов, заключается в том, что хеш-код будет иметь плохой дистрибутив.
Я сломаю свои вопросы:
a) Итак, рекомендуется ли переопределить GetHashCode
, если он используется в Dictionary
или выполняется ли реализация по умолчанию просто отлично?
b) У меня есть ссылочные типы, где это было бы легко сделать, поскольку у них есть поля, которые идентифицируют их однозначно, но как насчет тех ссылочных типов, где все члены также являются ссылочными типами. Что мне там делать?
Ответы
Ответ 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 на всякий случай.
Ответ 3
Взгляните на комментарий, который я оставил в статье: Метод расширения GetHashCode