Decimal.GetHashCode зависит от конечных нулей - программирование

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.

4b9b3361

Ответ 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, соответствующая статья обратной связи здесь.