Чи гарантоване повернення значення 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, вставляю той самий файл у нову директорію ... хеш-код виходить іншим, навіть жорстким, це той самий файл. Очевидно, його та сама версія. Єдине, що змінилося, - це шлях.