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

Уникальность Guid & GetHashCode

Учитывая следующий ключ:

int key = Guid.NewGuid().GetHashCode();

Является ли этот ключ уникальным как уникальность Guid?

4b9b3361

Ответ 1

принцип пигментации говорит нет. GUID имеет 16 байт информации - 128 бит. int содержит 32 бита информации. (EDIT: Чтобы уточнить из-за комментариев,.NET GUID позволит установить эти 128 бит произвольно, насколько мне известно, случайно созданные GUID следуют более строгим шаблонам, поэтому не существует 2 128 различные значения, которые были бы случайным образом сгенерированы. Тем не менее, более 2 32.)

Существует 2 128 возможных GUID и 2 32 возможных хеш-кодов - поэтому у вас не может быть другого хэш-кода для каждого GUID.

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

Было бы вполне справедливо для int.GetHashCode() возвращать (скажем) значение, деленное на два... так что -1, 0 и 1 будут получать хэш-код 0; 3 и 4 получили бы хэш-код 2 и т.д. Это было бы нехорошо (и это было бы медленнее, чем просто возврат значения), но это была бы действительная реализация. Он удовлетворяет всем ограничениям GetHashCode, а именно: если вы назовете его двумя равными значениями, он вернет тот же хэш-код.

Фактически, возвращение константы для всех значений является допустимой реализацией - хотя и довольно бесполезной, поскольку она обеспечивает нормальный поиск хэш-таблицы в операции O (N).

Ответ 2

GetHashCode() возвращает целое число - оно не может быть таким же уникальным, как Guid, поэтому нет - могут быть столкновения и уникальность не гарантируется.

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

Ответ 3

Как раз сегодня я заметил еще одну проблему с Guid.GetHashCode(): в реализации Microsoft.NET не каждый байт Guid хэширован: есть 6 байтов Guid, которые не хешированы, поэтому любое изменение одного из них никогда не изменит хэш-код.

Мы можем увидеть его в справочном источнике:

return _a ^ (((int)_b << 16) | (int)(ushort)_c) ^ (((int)_f << 24) | _k);

поэтому байты _d, _e, _g, _h, _i, _j не хэшируются. Это имеет важное значение для "последовательного" Guid s, например:

c482fbe1-9f16-4ae9-a05c-383478ec9d13
c482fbe1-9f16-4ae9-a05c-383478ec9d14
c482fbe1-9f16-4ae9-a05c-383478ec9d15
...
c482fbe1-9f16-4ae9-a05c-383478ec9dff
c482fbe1-9f16-4ae9-a05c-383478ec9e00
c482fbe1-9f16-4ae9-a05c-383478ec9e01

с Guid, как и у них, количество генерируемых хэшей очень невелико (256 различных значений), потому что 3478ec9d/3478ec9e не будет хэшироваться.

Ответ 4

A Guid - это 128-битное число. Int - это 32-битное число, поэтому оно не может быть "уникальным", как "Guid".

Кроме того, GetHashCode возвращает... хэш-код, он не должен быть уникальным. См. Другие обсуждения здесь о SO о том, почему GetHashCode() существует.

Ответ 5

У меня была именно проблема xanatos описывает в другом ответе. У меня есть класс, где два значения Guid используются для различения разных объектов, и я обнаружил, что получаю ужасное количество столкновений (мои Гиды не генерируются случайным образом). Вот код, который я использовал для решения проблемы. Guid1 и Guid2 - это свойства типа Guid, которые различают объекты. Код следует подход, описанный Джоном Скитом здесь.

    public override int GetHashCode()
    {
        int hash = 173;
        foreach (Byte b in Guid1.ToByteArray().Concat(Guid2.ToByteArray()))
        {
            hash = hash * 983 + b;
        }
        return hash;
    }