Что быстрее? глобальные или локальные переменные? - страница 3

 
GaryKaБолее того у вас в примере СPerson и SPerson вообще выступают в роли ключей (как Key). Для них ни в каком случае GetHeshCode() не будет вызван, только Equals() на некоторых этапах.

Ну дык, вроде приведенный Вами код показывает что GetHashCode() вызывается всякий раз, когда идет добавление в словарь нового CPerson. Другое дело, что Equals() не переопределен,  и добавление нового элемента прокатывает, т.к. по-умолчанию Equals() == ReferenceEquals(), а ссылки не равны. Т.е. уникальность элемента это GetHashCode + Equals. Вроде так получается.

Для иллюстрации примера, теперь попробуем переопределить Equals(), а GetHashCode() переопределять не будем. Значит, если хеш код не используется, то добавление в словарь вызовет ошибку времени исполнения, т.к. переопределенный Equals() всегда возвращает true:

class CPerson
    {
        public CPerson(string name)
        {
            mName = name;
        }

        public string Name
        {
            get { return mName; }
        }
        /// <summary>
        /// Внутреннее имя человека.
        /// </summary>
        private string mName;

        /*public override int GetHashCode()
        {
            Console.Out.WriteLine("GetHashCode() was called and returns 1");
            return 1;
        }*/
        public override bool Equals(object obj)
        {
            return true;
        }

    }

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

 
Не сразу нашелся, что ответить.

Пример очень интересный (проверял). Действительно и в java и в с# при добавление объекта в хеш-таблицу, верификация ключа (проверка на дубликаты ключей) в общем случае происходит так как вы указали сравнение по GetHashCode && сравнение по Equals.



Первым идет сравнение по хеш-коду. И если эта операция валиться (дефолтный хеш-код), то считаеться что добавляеться новый ключ, хотя по Equals() они могут быть эквивалентны. Как результат может произойти такой случай который вы описали в примере. Честно говоря этот код ни там ни там мне не нравиться, и я в ступоре от такой реализации в ядре обоих языков. Возможно на то были свои причины (моменты по performance).


В любом случае в java недопустимость такой ситуации (как в вашем примере) явно обозначена в документации. В с# не нашел (плохо знаю).




Немного теории в защиту своей позиции )).

От качества реализации функции хеширования, в теории должно зависеть только равномерность распределения хешей по корзинам (связаным спискам). Фунция хеширования используеться как функция понижающая размерность пространства ключей (в случае когда это пространство очень велико) в ассоциативном массиве. Если область допустимых значений ключей мала и известна заранее, то лучьше рассмотреть простые enumerations.

Вообщем если подитожить мой посыл: ваш пример скорее исключение, чем правило. И упаси вас бог, полагаться на идентификацию объекта по его хеш коду.
Полюбому спасибо за пример.