СЕКРЕТЫ И УЛОВКИ

Когда String.GetHashCode() в .NET C# сводит вас с ума

Знайте, когда следует зависеть от String.GetHashCode() в .NET C#, а когда нет.

История

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

Для хранения я использовал базу данных SQLite, в которой я сохраняю хэш-код сущности, представляющей мой класс транзакций. Я зависел от этого хэш-кода, так как в какой-то момент инструмент сгенерировал новый хэш-код и сравнил его с уже сохраненным в базе данных.

Итак, установив все на свои места, я запустил инструмент, попробуйте, да… он работает. Я закрываю инструмент, делаю кое-что, затем пытаюсь протестировать что-то другое, теперь оно не работает должным образом!!

Я пытался понять, что происходит, и, наконец, понял. Сравнение хэш-кода не работает нормально. Во время одного и того же сеанса работы инструмента сравнение работает нормально. Однако, когда я закрываю и открываю инструмент, вновь сгенерированный хэш-код для той же самой транзакции не совпадает с сохраненным в базе данных.

Я поискал в интернете и обнаружил, что это правда. По данным Майкрософт:

Стабильность самого хэш-кода не гарантируется. Хэш-коды для идентичных строк могут различаться в разных реализациях .NET, в разных версиях .NET и на разных платформах .NET (например, 32-разрядных и 64-разрядных) для одной версии .NET. В некоторых случаях они могут даже различаться доменом приложения. Это означает, что два последующих запуска одной и той же программы могут возвращать разные хэш-коды.

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

Наконец, не используйте хэш-код вместо значения, возвращаемого криптографической функцией хэширования, если вам нужен криптографически стойкий хэш. Для криптографических хэшей используйте класс, производный от класса System.Security.Cryptography.HashAlgorithm или System.Security.Cryptography.KeyedHashAlgorithm.

Для получения дополнительной информации о хеш-кодах см. Object.GetHashCode.

Поэтому сейчас я делюсь этим с вами и собираюсь рассказать вам, как по-хорошему преодолеть это.



Давайте попробуем

Создайте консольное приложение со следующим кодом.

Простой класс Employee с простой реализацией интерфейса IEquatable<Employee>.

Просто обратите внимание, как реализован метод GetHashCode.

При запуске приложения получаем вот что:

Теперь остановите приложение и запустите его снова. Вот что мы получаем:

Видите, оба результата не совпадают.

Правильный способ исправить это

Компаратор ArrayEqualityComparer‹T›

StringExtensions

ФиксированныйСотрудник

При запуске приложения получаем вот что:

Теперь остановите приложение и запустите его снова. Вот что мы получаем:

Видите, оба результата одинаковы.

Краткое содержание

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

Вот и все, надеюсь, вам было так же интересно читать эту историю, как мне было ее писать.

Надеюсь, вы нашли этот контент полезным. Если вы хотите поддержать:

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

Другие источники

Это другие ресурсы, которые могут оказаться полезными.