2012-07-02 28 views
16

thể trùng lặp:
C# Why can equal decimals produce unequal hash values?Decimal.GetHashCode phụ thuộc vào Trailing Zero

Tôi đã gặp sự cố trong tôi NET 3.5 ứng dụng (x86 hoặc x64, tôi đã cố gắng cả hai) trong đó số thập phân có số lượng dấu 0 khác nhau có các mã băm khác nhau. Ví dụ:

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

đầu ra sau trên máy tính của tôi:

1085009409 
1085009408 
True 
False 

tôi đoán sự khác biệt về mã băm là xuống đến cơ quan đại diện nội bộ khác nhau của hai con số gây ra bởi các yếu tố quy mô khác nhau.

Trong khi tôi có thể khắc phục sự cố bằng cách xóa các số không theo sau, tôi luôn giả định rằng GetHashCode phải trả về cùng giá trị cho x và y, nếu x == y. Giả định này sai, hay đây là một vấn đề với Decimal.GetHashCode?

EDIT: Để rõ ràng trên các phiên bản tôi đang sử dụng Visual Studio 2008 SP1, .NET 3.5.

+1

Đây có phải là mã thực của bạn không? Điều này trả về '1085009408, 1085009408, True True' cho tôi. - Chỉnh sửa: đó là .NET 4, các kết quả khác nhau trên .NET 3.5 đã được xác nhận. – CodeCaster

+0

Tôi nhận được kết quả tương tự như OP trên .NET 3.5. @CodeCaster, bạn đang chạy phiên bản nào? – Servy

+1

Vì vậy, tôi đã đi và xem xét các bit thập phân và chúng khác nhau cho x và y (với .NET trước 3.5). Rõ ràng phương thức 'Equals' cho sự khác biệt này, nhưng' GetHashCode' thì không. – Servy

Trả lời

12

Đây là sự cố với Decimal.GetHashCode, cho .NET Framework phiên bản 3.5 trở xuống. Khi hai giá trị được coi là bằng nhau, chúng phải trả lại mã băm giống nhau, theo hướng dẫn; trong trường hợp này, decimal rõ ràng là không. Bạn nên luôn mong đợi hai đối tượng bằng nhau để có cùng mã băm.

Per MSDN:

Nếu hai vật thể so sánh như bình đẳng, phương pháp GetHashCode cho từng đối tượng phải trả về giá trị tương tự.

tái

Tôi đã thử mã chính xác của bạn chống lại các phiên bản khác nhau của .NET Framework, và kết quả là:

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

Nói cách khác, có vẻ như bạn stumbled khi một lỗi trong Khuôn khổ .NET đã được khắc phục bằng .NET Framework 4.

Các kết quả trên đã đạt được bằng cách sử dụng Visual Studio 2012 RC, sử dụng các trang thuộc tính để chuyển đổi khung công tác.

Microsoft acknowledges the bug here.

+0

Tôi cũng thấy các tài liệu đó nên tôi cho rằng nó phải là một lỗi, nhưng tôi nghĩ tôi sẽ có một số ý kiến ​​khác ở đây trước; lỗi trong .NET là khá hiếm sau khi tất cả! – MrKWatkins

+0

Nó thực sự trông giống như nó là một lỗi, đó là cố định với phiên bản hiện tại; xem cập nhật cho câu trả lời. – driis

+0

Cảm ơn công việc của bạn ở đây, được nhiều người đánh giá cao. Một lý do khác để nâng cấp lên .NET 4 ... – MrKWatkins

9

Đây là phiên bản .NET infamous bug trong phiên bản .NET trước .NET. Triển khai Decimal.GetHashCode() có phụ thuộc vào giá trị bit trong giá trị thập phân. Chúng khác nhau vì số thập phân theo dõi số chữ số đã biết trong phân số. Một cái gì đó bạn có thể nhìn thấy bằng cách sử dụng Decimal.GetBits() trên các giá trị. Nó thực sự gây tranh cãi cho dù đây là một lỗi, các số thập phân do có giá trị khác nhau, tùy thuộc vào loại kính bạn đeo.

Tuy nhiên, Microsoft đồng ý rằng đây là hành vi không trực quan và đã khắc phục nó trong .NET 4, bài viết phản hồi có liên quan is here.

+0

Tôi nhận thấy vấn đề do chơi với GetBits; từ quan điểm đó, chúng chắc chắn rất khác nhau, điều này đã gây ra cho tôi một vài cơn đau đầu ... Tôi đã không nhận thấy vấn đề GetHashCode trong một thời gian mặc dù đối với rất nhiều dấu 0, chúng tạo ra cùng một mã băm. .. Ví dụ: 3575 với 0 -> 17 hoặc 19 -> 22 dấu 0 cho tất cả các mã băm giống nhau nhưng có kết quả GetBits khá khác nhau(). Rất thích xem thực hiện GetHashCode thực tế vì vậy tôi có thể làm việc tại sao ... – MrKWatkins

+1

Tải về SSCLI20, clr/src/vm/comdecimal.cpp tập tin mã nguồn, COMDecimal :: GetHashCode() chức năng. –

+0

Tuyệt vời, cảm ơn bạn! – MrKWatkins

Các vấn đề liên quan