/ / Чи можу я залежати від значень GetHashCode (), щоб бути послідовними? - c #, хеш

Чи можу я залежати від того, щоб значення GetHashCode () були послідовними? - c #, хеш

Чи гарантоване повернення значення GetHashCode () узгодженим, якщо застосовується одне і те ж значення рядка? (C # / ASP.NET)

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

Відповіді:

29 для відповіді № 1

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

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

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


10 за відповідь № 2

У мене була подібна проблема, коли я заповнив базу данихтаблиця з інформацією, яка залежала від 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 для відповіді № 3

Реалізація залежить від версії фреймворку, але також залежить від архітектури. Реалізація string.GetHashCode () відрізняється у версіях фреймворку x86 та x64, навіть якщо вони мають однаковий номер версії.


1 для відповіді № 4
    /// <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 для відповіді № 5

Цікаво, чи є відмінності між 32-розрядною та 64-розрядною операційними системами, оскільки я впевнений, що і на моєму сервері, і на домашньому комп’ютері працює одна і та ж версія .NET

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


0 для відповіді № 6

Ви використовуєте Win2008 x86 як робочий стіл? Тому що Win2008 включає версію 2.0.50727.1434, яка є оновленою версією 2.0, включеною в Vista RTM.


0 для відповіді № 7

Однак, що ми помітили, коли об'єкт знаходиться вхешована колекція об'єкт (хеш-таблиця, словник тощо), коли 2 об’єкти не є унікальними але їхні хеш-коди є, хеш-код використовується лише як перший варіант пошуку, якщо є не унікальні хеш-коди використовується оператор рівності завжди використовується як падіння назад до детирмінова рівність.

Це спосіб роботи хеш-пошуку, правда? Кожне сегмент містить список елементів, що мають однаковий хеш-код.

Тож для пошуку правильного елемента за цих умов відбувається лінійний пошук із використанням порівняння рівності значень.

І якщо ваша реалізація хешування досягає хорошого розподілу, цей пошук не потрібен, тобто один елемент на відро.

Чи правильне моє розуміння?


0 для відповіді № 8

Не пряма відповідь на ваше запитання, на яке Йонас відповів добре, проте це може допомогти, якщо вас турбує тестування на рівність у хешах

З наших тестів, залежно від того, що вам потрібно з хеш-кодами, в C # хеш-коди не повинні бути унікальними для операцій рівності. Як приклад розглянемо наступне:

У нас була вимога перевантажити рівнихоператора, а отже і функція GetHashCode наших об'єктів, оскільки вони стали нестабільними та без стану, а також отримують джерела безпосередньо з даних, тому в одному місці програми нам потрібно було переконатись, що об'єкт буде розглядатися як рівний іншому об'єкту якщо це було отримано з тих самих даних, не просто якби це було те саме посилання. Наші унікальні ідентифікатори даних - це Посібники.

Оператора equals було легко задовольнити, оскільки ми щойно перевірили в Guid запису (після перевірки на нуль).

На жаль, розмір даних HashCode (будучиint) залежить від операційної системи, а для нашої 32-розрядної системи хеш-код буде 32-розрядним. Математично, коли ми замінюємо функцію GetHashCode, неможливо створити унікальний хеш-код з гіда, який перевищує 32 біт (подивіться на нього з навпаки, як би ви перевели 32 бітове ціле число в гід?).

Потім ми провели кілька тестів, де взяли Guid як рядок і повернули HashCode Guid, який майже завжди повертає унікальний ідентифікатор у наших тестах, але не завжди.

Що ми помітили, однак, коли об'єкт знаходитьсяхешований об'єкт колекції (хеш-таблиця, словник тощо), коли 2 об'єкти не є унікальними, але їх хеш-коди є, хеш-код використовується лише як перший варіант пошуку, якщо використовуються не-унікальні хеш-коди, оператор рівності завжди використовується як повернення до детермінної рівності.

Як я вже говорив, це може бути чи не стосуватися вашої ситуації, але якщо це так, це корисна порада.

UPDATE

Для демонстрації ми маємо Hashtable:

Ключ: об'єкт A (хеш-код 1), значення об'єкта A1

Ключ: об'єкт B (хеш-код 1), значення об'єкта B1

Ключ: об'єкт C (хеш-код 1), значення об'єкта C1

Ключ: об'єкт D (хеш-код 2), значення об'єкта D1

Ключ: об'єкт E (хеш-код 3), значення об'єкта E1

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

Коли я викликаю хеш-таблицю для об'єкта за допомогою ключа Object D, об'єкт D1 буде повернутий через 1 крок, пошук хешу


-1 для відповіді № 9

Я мав би сказати ... ти не можеш на це покладатися.Наприклад, якщо я запускаю файл1 через хеш-код md5 c # "s і копіюю nd, вставляю той самий файл у нову директорію ... хеш-код виходить іншим, навіть жорстким, це той самий файл. Очевидно, його та сама версія. Єдине, що змінилося, - це шлях.