Могу ли я зависеть от того, чтобы значения GetHashCode () были согласованными? - PullRequest
15 голосов
/ 10 сентября 2008

Гарантируется ли возвращаемое значение GetHashCode () согласованным, если используется то же строковое значение? (С # / ASP.NET)

Сегодня я загрузил свой код на сервер, и, к моему удивлению, мне пришлось переиндексировать некоторые данные, поскольку мой сервер (64-разрядная версия win2008) возвращал другие значения по сравнению с моим настольным компьютером.

Ответы [ 9 ]

31 голосов
/ 10 сентября 2008

Если я не ошибаюсь, GetHashCode непротиворечив, учитывая одно и то же значение, но он НЕ гарантированно непротиворечив в разных версиях фреймворка.

Из документов MSDN на String.GetHashCode ():

Поведение GetHashCode зависит от его реализации, которая может меняться от одной версии общеязыковой среды выполнения к другой. Причина, по которой это может произойти, заключается в улучшении производительности GetHashCode.

11 голосов
/ 07 мая 2009

У меня была похожая проблема, когда я заполнял таблицу базы данных информацией, которая зависела от String.GetHashCode (не самая лучшая идея), и когда я обновил сервер, на котором работал, до x64, я заметил значения, полученные от String. .GetHashCode не соответствовал тому, что уже было в таблице. Моим решением было использовать мою собственную версию GetHashCode, которая возвращает то же значение, что и String.GetHashCode в платформе x86.

Вот код, не забудьте скомпилировать с «Разрешить небезопасный код»:

    /// <summary>
    /// Similar to String.GetHashCode but returns the same as the x86 version of String.GetHashCode for x64 and x86 frameworks.
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static unsafe int GetHashCode32(string s)
    {
        fixed (char* str = s.ToCharArray())
        {
            char* chPtr = str;
            int num = 0x15051505;
            int num2 = num;
            int* numPtr = (int*)chPtr;
            for (int i = s.Length; i > 0; i -= 4)
            {
                num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
                if (i <= 2)
                {
                    break;
                }
                num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
                numPtr += 2;
            }
            return (num + (num2 * 0x5d588b65));
        }
    }
5 голосов
/ 19 февраля 2009

Реализация зависит от версии платформы, но также зависит от архитектуры . Реализация string.GetHashCode () отличается в версиях платформы x86 и x64, даже если они имеют одинаковый номер версии.

0 голосов
/ 21 августа 2013
    /// <summary>
    /// Default implementation of string.GetHashCode is not consistent on different platforms (x32/x64 which is our case) and frameworks. 
    /// FNV-1a - (Fowler/Noll/Vo) is a fast, consistent, non-cryptographic hash algorithm with good dispersion. (see http://isthe.com/chongo/tech/comp/fnv/#FNV-1a)
    /// </summary>
    private static int GetFNV1aHashCode(string str)
    {
        if (str == null)
            return 0;
        var length = str.Length;
        // original FNV-1a has 32 bit offset_basis = 2166136261 but length gives a bit better dispersion (2%) for our case where all the strings are equal length, for example: "3EC0FFFF01ECD9C4001B01E2A707"
        int hash = length;
        for (int i = 0; i != length; ++i)
            hash = (hash ^ str[i]) * 16777619;
        return hash;
    }

Эта реализация может быть медленнее, чем небезопасная, опубликованная ранее. Но гораздо проще и безопаснее.

0 голосов
/ 15 ноября 2009

Я бы сказал ... Вы не можете на это полагаться. Например, если я запускаю file1 через хэш-код md5 в c # и копирую и вставляю тот же файл в новый каталог ... хеш-код получается другим, даже если это тот же файл. Очевидно, это та же версия .net, все то же самое. Единственное, что изменилось, это путь.

0 голосов
/ 10 сентября 2008

Что мы заметили, однако, когда объект находится в хешированной коллекции объект (хеш-таблица, словарь и т. д.), когда 2 объекта не являются уникальными но их хэш-коды, хеш-код используется только в качестве первого варианта поиска, если есть неуникальные хеш-коды используется оператор равенства всегда используется как отступление детирмин равенство.

Так работает поиск хешей, верно? Каждое ведро содержит список элементов, имеющих одинаковый хэш-код.

Таким образом, чтобы найти правильный пункт в этих условиях, выполняется линейный поиск с использованием сравнения на равенство значений.

И если ваша реализация хеширования достигает хорошего распределения, этот поиск не требуется, т. Е. Один элемент на группу.

Правильно ли мое понимание?

0 голосов
/ 10 сентября 2008

Не прямой ответ на ваш вопрос, на который Йонас ответил хорошо, однако это может помочь, если вы беспокоитесь о проверке на равенство в хешах

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

У нас было требование перегрузить оператор equals, и, следовательно, функцию GetHashCode наших объектов, поскольку они стали изменчивыми и не сохраняющими состояние, и извлекали себя непосредственно из данных, поэтому в одном месте приложения нам нужно было убедиться, что объект будет рассматриваться как равный другому объекту , если он получен из тех же данных , а не только, если это была та же ссылка. Наши уникальные идентификаторы данных - Guids.

Оператор equals был прост в обслуживании, поскольку мы только что проверили Guid записи (после проверки на ноль).

К сожалению, размер данных HashCode (будучи целочисленным) зависит от операционной системы, а в нашей 32-битной системе хэш-код будет 32-битным. Математически, когда мы переопределяем функцию GetHashCode, невозможно сгенерировать уникальный хеш-код из guid, который больше 32 бит (посмотрите на это из обратного, как бы вы перевели 32-битное целое число в guid?).

Затем мы провели несколько тестов, в которых мы взяли Guid в качестве строки и вернули HashCode of Guid, который почти всегда возвращает уникальный идентификатор в наших тестах, но не всегда.

Что мы заметили, однако, когда объект находится в хешированном объекте коллекции (хеш-таблица, словарь и т. Д.), Когда 2 объекта не являются уникальными, но их хеш-коды есть, хеш-код используется только в качестве первого варианта поиска, если используются неуникальные хеш-коды, оператор равенства всегда используется в качестве отступления для определения равенства .

Как я уже сказал, это может или не может иметь отношение к вашей ситуации, но если это полезный совет.

UPDATE

Для демонстрации у нас есть Hashtable:

Ключ: объект A (хэш-код 1), значение объекта A1

Ключ: объект B (хэш-код 1), значение объекта B1

Ключ: объект C (хэш-код 1), значение объекта C1

Ключ: объект D (хэш-код 2), значение объекта D1

Ключ: объект E (хэш-код 3), значение объекта E1

Когда я вызываю хеш-таблицу для объекта с ключом Объекта A, объект A1 будет возвращен через 2 шага, вызов для хеш-кода 1, затем проверка на равенство для ключевого объекта, поскольку не существует уникального ключа с хеш-код 1

Когда я вызываю хеш-таблицу для объекта с ключом Объекта D, объект D1 будет возвращен через 1 шаг, поиск по хешу

0 голосов
/ 10 сентября 2008

Вы используете Win2008 x86 в качестве рабочего стола? Потому что Win2008 включает в себя версию 2.0.50727.1434 , которая является обновленной версией 2.0, включенной в Vista RTM.

0 голосов
/ 10 сентября 2008

Интересно, существуют ли различия между 32-разрядными и 64-разрядными операционными системами, потому что я уверен, что и на моем сервере, и на домашнем компьютере установлена ​​одна и та же версия .NET

Я всегда устал от использования GetHashCode (), для меня было бы хорошей идеей просто использовать свой собственный алгоритм хэширования. Ну, по крайней мере, в результате я написал страницу быстрого переиндексации .aspx из-за этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...