Decimal.GetHashCode зависит от конечных нулей
Возможный дубликат:
С# Почему одинаковые десятичные знаки производят неравные хеш-значения?
Я столкнулся с проблемой в своем приложении .NET 3.5 (x86 или x64, я пробовал оба), где десятичные числа с другим количеством конечных нулей имеют разные хеш-коды. Например:
decimal x = 3575.000000000000000000M;
decimal y = 3575.0000000000000000000M;
Console.WriteLine(x.GetHashCode());
Console.WriteLine(y.GetHashCode());
Console.WriteLine(x == y);
Console.WriteLine(x.GetHashCode() == y.GetHashCode());
Выводит на моем компьютере следующее:
1085009409
1085009408
True
False
Я предполагаю, что разница в хэш-кодах сводится к различным внутренним представлениям двух чисел, вызванных различными масштабными коэффициентами.
В то время как я могу обойти проблему, удалив конечные нули, я всегда предполагал, что GetHashCode должен возвращать одно и то же значение для x и y, если x == y. Это предположение неверно, или это проблема с Decimal.GetHashCode?
EDIT: чтобы быть понятным в версиях, я использую Visual Studio 2008 SP1,.NET 3.5.
Ответы
Ответ 1
Это проблема с Decimal.GetHashCode
, для .NET Framework версии 3.5 и ниже. Когда два значения считаются равными, они должны возвращать один и тот же хэш-код в соответствии с рекомендациями; в этом случае decimal
явно нет. Вы всегда должны ожидать, что два одинаковых объекта имеют одинаковый хеш-код.
В MSDN:
Если два объекта сравниваются как равные, метод GetHashCode для каждого объект должен вернуть одно и то же значение.
воспроизводящего
Я пробовал ваш точный код для разных версий .NET Framework, и результаты:
╔══════════════════╤══════════════════╗
║Framework version │ Hashcode equal ? ║
╟──────────────────┼──────────────────╢
║ 2.0 │ No. ║
║ 3.0 │ No. ║
║ 3.5 │ No. ║
║ 4.0 │ Yes. ║
║ 4.5 │ Yes. ║
╚══════════════════╧══════════════════╝
Другими словами, кажется, что вы наткнулись на ошибку в платформе .NET, которая была исправлена с .NET Framework 4.
Вышеуказанные результаты были достигнуты с использованием Visual Studio 2012 RC, используя страницы свойств для переключения рамки.
Microsoft подтверждает ошибку здесь.
Ответ 2
Это была довольно известная ошибка в версиях .NET до .NET 4. Реализация Decimal.GetHashCode() зависела от значений бит в десятичной системе стоимость. Они отличаются друг от друга, так как десятичные числа отслеживают количество известных цифр во фракции. Что-то, что вы можете увидеть, используя значения Decimal.GetBits() для значений. Это на самом деле спорно, является ли это ошибка, десятые действительно имеют разные значения, в зависимости от того, какие очки вы носите.
Тем не менее, Microsoft согласилась с тем, что это было неинтуитивное поведение и исправлено в .NET 4, соответствующая статья обратной связи здесь.