2012-12-28 17 views
8

Nếu có một liệt kê được lưu trữ bên trong một loại tổng hợp, người ta có thể muốn bao gồm điều đó bên trong mã băm của loại (giả sử một hàm băm "multiply by primes" điển hình). Nếu một cuộc gọi chỉ gọi SomeEnum.GetHashCode(), có vẻ như các hộp JIT thể hiện, ngay cả trong bản phát hành bản phát hành.Làm cách nào để truy xuất mã băm của một liệt kê mà không có quyền anh?

Việc lập hồ sơ này cho thấy khoảng 10% thời gian đơn đăng ký của tôi đã dành số liệt kê quyền anh trong các hàm GetHashCode khác nhau.

Một số loại giá trị triển khai IEquatable hoặc các giao diện tương tự, cho phép gọi GetHashCode làm phương pháp tĩnh; mà tránh đấm bốc. Nhưng System.Enum không cung cấp quá tải tĩnh của GetHashCode. Có một số phương tiện tính toán mã mà nên được sử dụng nhưng tránh được quyền anh?

+2

Tại sao phải bận tâm? Enum là mã băm riêng của nó. Chỉ cần cast vào int và gọi nó là một ngày. –

+0

@Raymond: Tôi nghĩ rằng có thể dẫn đến sự phân phối không tốt; nhưng suy nghĩ lại về nó một lần nữa tôi sẽ xem nó có hoạt động không. –

+0

@Raymond: Điều đó thực sự hiệu quả đối với trường hợp thử nghiệm cụ thể này. Tôi đang để mở này mặc dù trong một thời gian ... –

Trả lời

4

Bạn có thể biến đổi thành kiểu cơ bản của enum (thường int trừ khi định nghĩa enum quy định cụ thể khác) và sử dụng ghi đè GetHashCode() phương pháp của loại đó.

enum TestEnum 
{ 
    Test1, 
    Test2 
} 

TestEnum t = TestEnum.Test1; 
((int)t).GetHashCode(); // no boxing 
t.GetHashCode(); // boxing 

Đây là IL cho mã này:

IL_0000: nop 
IL_0001: ldc.i4.0 
IL_0002: stloc.0 
IL_0003: ldloc.0 
IL_0004: stloc.1 
IL_0005: ldloca.s V_1 
IL_0007: call  instance int32 [mscorlib]System.Int32::GetHashCode() 
IL_000c: pop 
IL_000d: ldloc.0 
IL_000e: box  ConsoleApplication1.Program/TestEnum 
IL_0013: callvirt instance int32 [mscorlib]System.Object::GetHashCode() 
IL_0018: pop 
IL_0019: ret 

Edit: Để hoàn chỉnh, tôi phải chỉ ra rằng cơ thể của int.GetHashCode() chỉ đơn giản là return this;, như vậy là Raymond Chen đã chỉ ra trong một bình luận ở trên, chỉ cần đúc enum vào một int là đủ tốt để có được một mã băm.

+0

Điều này có thực sự tránh được quyền anh? (ví dụ: không 'int.GetHashCode()' cũng dẫn đến quyền anh?) –

+0

Có, điều này tránh boxing. Đúc từ một enum đến một int tránh boxing (tham khảo chú thích đầu tiên của Jon Skeet: http://bytes.com/topic/c-sharp/answers/276556-enum-vs-constants-performance) và gọi GetHashCode trên một int không gây boxing hoặc kể từ khi GetHashCode được ghi đè cho cấu trúc này (và tôi thậm chí còn giải mã việc thực hiện nó, và nó không làm bất cứ điều gì có thể gây ra một hoạt động boxing). Việc gọi phiên bản Enum của GetHashCode thực tế là gây ra boxing (như bạn đã lưu ý) bởi vì nó gọi một phương thức nội bộ trả về một 'đối tượng', sau đó gọi' GetHashCode() 'trên nó. – jam40jeff

+0

Nhân tiện, tôi đã kiểm tra sai việc thực hiện 'GetHashCode()' cho 'short' trước khi tôi đăng. Việc thực hiện cho 'int' chỉ đơn giản là' trả về điều này; ', vì vậy (như Raymond Chen đã nhận xét) bạn chỉ có thể truyền giá trị Enum tới' int' và sử dụng nó làm mã băm của bạn. – jam40jeff

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