2012-07-02 25 views
16

Mögliche Duplizieren:
C# Why can equal decimals produce unequal hash values?Decimal.GetHashCode hängt davon ab Rollier Zeros

ich auf ein Problem in meiner .NET 3.5-Anwendung (x86 oder x64 gekommen sind, habe ich versucht, beide), wobei Dezimalstellen mit einer anderen Anzahl von nachgestellten Nullen unterschiedliche Hash-Codes haben. Zum Beispiel:

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()); 

Ausgänge folgend auf meinem Rechner:

1085009409 
1085009408 
True 
False 

Ich nehme den Unterschied in der Hash-Codes ist bis auf die verschiedenen internen Darstellungen der beiden Zahlen durch die unterschiedlichen Skalierungsfaktoren verursacht.

Während ich das Problem umgehen kann, indem ich die abschließenden Nullen entferne, nahm ich immer an, dass GetHashCode den gleichen Wert für x und y zurückgeben sollte, wenn x == y. Ist diese Annahme falsch oder ist das ein Problem mit Decimal.GetHashCode?

EDIT: Um auf Versionen klar zu sein, verwende ich Visual Studio 2008 SP1, .NET 3.5.

+1

Ist dies Ihr tatsächlicher Code? Dies gibt '1085009408, 1085009408, True True 'für mich zurück. - Edit: das war .NET 4, verschiedene Ergebnisse auf .NET 3.5 bestätigt. – CodeCaster

+0

Ich habe die gleiche Ausgabe wie das OP auf .NET 3.5. @CodeCaster, in welcher Version läuft es? – Servy

+1

Also ging ich und schaute auf die Bits der Dezimalstelle und sie sind unterschiedlich für x und y (mit. NET vor 3.5). Offensichtlich erklärt die "Equals" -Methode diesen Unterschied, aber der "GetHashCode" nicht. – Servy

Antwort

12

Dies ist ein Problem mit Decimal.GetHashCode, für .NET Framework, Version 3.5 und niedriger. Wenn zwei Werte gleich sind, müssen sie den gleichen Hash-Code gemäß den Richtlinien zurückgeben. in diesem Fall, decimal eindeutig nicht. Sie sollten immer erwarten, dass zwei gleiche Objekte denselben Hash-Code haben.

Per MSDN:

Wenn zwei Objekte zu vergleichen, als gleich, denselben Wert zurückgeben die GetHashCode Methode für jedes Objekt muss.

Die Reproduktion ist

Ich habe Ihre genauen Code gegen verschiedene Versionen des .NET Framework versucht, und die Ergebnisse sind:

╔══════════════════╤══════════════════╗ 
║Framework version │ Hashcode equal ? ║ 
╟──────────────────┼──────────────────╢ 
║  2.0   │ No.    ║ 
║  3.0   │ No.    ║ 
║  3.5   │ No.    ║ 
║  4.0   │ Yes.   ║ 
║  4.5   │ Yes.   ║ 
╚══════════════════╧══════════════════╝ 

Mit anderen Worten, es scheint, dass Sie auf einen Fehler gestolpert Das .NET-Framework, das mit .NET Framework 4 behoben wurde.

Die obigen Ergebnisse wurden mit Visual Studio 2012 RC erreicht, mithilfe der Eigenschaftenseiten, um das Framework zu wechseln.

Microsoft acknowledges the bug here.

+0

Ich habe diese Dokumente auch gesehen, also habe ich angenommen, dass es ein Fehler sein muss, aber ich dachte, ich würde zuerst ein paar andere Meinungen dazu bekommen; Fehler in .NET sind ziemlich selten! – MrKWatkins

+0

Es sieht tatsächlich so aus, als wäre es ein Bug, der mit der aktuellen Version behoben wird; Siehe Update zur Antwort. – driis

+0

Vielen Dank für Ihre Arbeit hier, sehr geschätzt. Ein weiterer Grund, auf .NET 4 zu aktualisieren ... – MrKWatkins

9

Dies war eine ziemlich infamous bug in .NET-Versionen vor .NET 4. Die Decimal.GetHashCode() - Implementierung hatte eine Abhängigkeit von den Bit-Werten im Dezimalwert. Sie unterscheiden sich, da Dezimalzahlen die Anzahl der bekannten Ziffern im Bruch nachverfolgt. Etwas, das Sie sehen können, indem Sie Decimal.GetBits() für die Werte verwenden. Es ist tatsächlich fraglich, ob das ein Fehler ist, die Dezimalzahlen do haben unterschiedliche Werte, je nachdem, welche Art von Brille Sie tragen.

Dennoch stimmte Microsoft zu, dass dies ein nicht intuitives Verhalten war und es in .NET 4, dem relevanten Feedback-Artikel is here, behoben wurde.

+0

Ich bemerkte das Problem aufgrund des Spiels mit GetBits; Von diesem Standpunkt aus sind sie definitiv sehr unterschiedlich, was mir einige Kopfschmerzen bereitet hat ... Ich habe das GetHashCode-Problem für eine Weile nicht bemerkt, aber für viele nachfolgende Nullen produzieren sie den gleichen Hash-Code. .. Zum Beispiel 3575 mit 0 -> 17 oder 19 -> 22 abschließenden Nullen geben alle den gleichen Hash-Code, haben aber ganz andere GetBits() - Ergebnisse. Ich würde gerne die tatsächliche GetHashCode-Implementierung sehen, so dass ich herausfinden könnte, warum ... – MrKWatkins

+1

Download SSCLI20, clr/src/vm/comdecimal.cpp Quellcodedatei, COMDecimal :: GetHashCode() -Funktion. –

+0

Ausgezeichnet, danke! – MrKWatkins

Verwandte Themen