2008-09-09 26 views
14

Giá trị trả về của GetHashCode() có được đảm bảo là giả định giá trị chuỗi giống nhau đang được sử dụng không? (C#/ASP.NET)Tôi có thể phụ thuộc vào các giá trị của GetHashCode() để phù hợp không?

Tôi đã tải mã của mình lên máy chủ hôm nay và tôi ngạc nhiên là phải kết nối lại dữ liệu vì máy chủ (win2008 64-bit) đã trả về các giá trị khác so với máy tính để bàn của tôi.

Trả lời

29

Nếu tôi không nhầm, GetHashCode phù hợp với cùng một giá trị, nhưng KHÔNG được đảm bảo nhất quán trên các phiên bản khác nhau của khung công tác.

Từ các tài liệu MSDN trên String.GetHashCode():

Hành vi của GetHashCode là phụ thuộc vào việc thực hiện, mà có thể thay đổi từ một phiên bản của bộ thực thi ngôn ngữ chung khác. Lý do tại sao điều này có thể xảy ra là cải thiện hiệu suất của GetHashCode.

+1

Kết luận: Không bao giờ tồn tại hoặc truyền kết quả của 'GetHashCode()'. Chỉ sử dụng nó cho mục đích dự định của nó: để tạo thuận lợi cho việc sử dụng các bảng băm. –

0

Tôi tự hỏi nếu có sự khác biệt giữa các hệ điều hành 32-bit và 64-bit, vì tôi chắc chắn cả hai máy chủ của tôi và máy tính ở nhà đang chạy cùng một phiên bản của .NET

Tôi luôn luôn cảm thấy mệt mỏi bằng cách sử dụng GetHashCode(), nó có thể là một ý tưởng tốt cho tôi để chỉ đơn giản là vai trò thuật toán băm của riêng tôi. Ít nhất tôi đã kết thúc viết một trang index .aspx nhanh chóng vì nó.

0

Bạn có đang chạy Win2008 x86 làm máy tính để bàn không? Bởi vì Win2008 bao gồm phiên bản 2.0.50727.1434, là phiên bản cập nhật 2.0 bao gồm trong Vista RTM.

0

Không phải là một câu trả lời trực tiếp câu hỏi của bạn, mà Jonas đã trả lời tốt, tuy nhiên điều này có thể hỗ trợ nếu bạn đang lo lắng về việc thử nghiệm bình đẳng trong băm

Từ bài kiểm tra của chúng tôi, tùy thuộc vào những gì bạn đang cần với hashcodes, trong C#, hashcodes không cần phải là duy nhất cho các hoạt động bình đẳng. Ví dụ, hãy xem xét những điều sau đây:

Chúng tôi đã có yêu cầu quá tải toán tử bằng, và do đó chức năng GetHashCode của đối tượng của chúng tôi đã trở nên dễ bay hơi và không quốc tịch, và tìm nguồn trực tiếp từ dữ liệu, ở một nơi ứng dụng chúng tôi cần để đảm bảo rằng một đối tượng sẽ được xem bằng với một đối tượng khác nếu nó được lấy từ cùng một dữ liệu, không chỉ khi nó là cùng một tham chiếu. Số nhận dạng dữ liệu duy nhất của chúng tôi là Hướng dẫn.

Toán tử bằng được dễ dàng phục vụ vì chúng tôi vừa kiểm tra hướng dẫn của bản ghi (sau khi kiểm tra giá trị rỗng).

Không may kích thước dữ liệu HashCode (là int) phụ thuộc vào hệ điều hành và trên hệ thống 32 bit của chúng tôi, mã băm sẽ là 32 bit. Về mặt toán học, khi chúng ta ghi đè hàm GetHashCode, không thể tạo ra một mã băm duy nhất từ ​​một guid lớn hơn 32 bit (xem nó từ cuộc trò chuyện, làm thế nào bạn dịch một số nguyên 32 bit thành một guid?). Sau đó, chúng tôi đã thực hiện một số thử nghiệm trong đó chúng tôi lấy Guid làm chuỗi và trả về mã Hashcode của Guid, hầu như luôn trả về một mã định danh duy nhất trong các thử nghiệm của chúng tôi, nhưng không phải lúc nào cũng như vậy.Tuy nhiên, những gì chúng tôi đã thông báo, khi một đối tượng nằm trong đối tượng thu thập băm (một hashtable, một từ điển, v.v.), khi 2 đối tượng không phải là duy nhất nhưng hashcodes của chúng là hashcode chỉ được sử dụng như tra cứu tùy chọn đầu tiên, nếu có mã băm không phải là duy nhất đang được sử dụng, thì toán tử bình đẳng sẽ luôn được sử dụng như là một sự sụp đổ để xác nhận sự bình đẳng.

Như tôi đã nói điều này có thể hoặc có thể không liên quan đến tình huống của bạn, nhưng nếu đó là một mẹo hữu ích.

CẬP NHẬT

Để minh hoạ, chúng tôi có một Hashtable:

chính: Object A (Mã lệnh bí mật 1), giá trị Object A1

chính: Object B (Mã lệnh bí mật 1), giá trị Object B1

chính: Object C (Mã lệnh bí mật 1), giá trị Object C1

chính: Object D (Mã lệnh bí mật 2), giá trị Ob JECT D1

chính: Object E (Mã lệnh bí mật 3), giá trị Object E1

Khi tôi gọi là Hashtable cho đối tượng với phím của Object A, đối tượng A1 sẽ được trả lại sau 2 bước, một lời kêu gọi hashcode 1, sau đó kiểm tra bình đẳng trên đối tượng khóa vì không có khóa duy nhất với mã băm 1

Khi tôi gọi hàm bắt đầu cho đối tượng bằng khóa của Object D, đối tượng D1 sẽ được trả về sau 1 bước , một tra cứu băm

0

Tuy nhiên, chúng tôi đã thông báo khi một sốĐối tượngnằm trong một bộ sưu tập băm đối tượng (một hashtable, một từ điển vv), khi 2 đối tượng không phải là duy nhất nhưng mã băm của chúng là, mã băm chỉ được sử dụng như tra cứu tùy chọn đầu tiên, mã băm đang được sử dụng, toán tử bình đẳng là luôn được sử dụng để giảm trở lại xác nhận sự bình đẳng.

Đây là cách tìm kiếm hàm băm hoạt động, đúng không? Mỗi nhóm chứa danh sách các mục có cùng mã băm.

Vì vậy, để tìm đúng mục trong các điều kiện này, tìm kiếm tuyến tính bằng cách sử dụng so sánh giá trị bình đẳng diễn ra.

Và nếu triển khai băm của bạn đạt được phân phối tốt, tìm kiếm này không bắt buộc, nghĩa là một mục cho mỗi nhóm.

Sự hiểu biết của tôi có đúng không?

+0

Ben, từ thử nghiệm của chúng tôi, điều này là đúng sự thật. Tìm kiếm bình đẳng thứ hai chỉ chạy theo yêu cầu. Bạn có thể tự kiểm tra nó bằng cách nạp chồng ==,! =, Equals() và GetHashCode của một đối tượng nào đó. Tôi thấy nó rất thú vị (nhưng tôi là một geek :)) – johnc

+0

(tiếp theo), do đó, hiệu ứng của mã băm nonunique sẽ chậm hơn để chạy kiểm tra bình đẳng, nhưng trong trường hợp của chúng tôi, nơi giá trị phi thường rất hiếm, nó phần lớn không đáng kể – johnc

5

Việc triển khai phụ thuộc vào phiên bản của khung nhưng cũng phụ thuộc vào architecture. Việc thực hiện string.GetHashCode() là dfferent trong các phiên bản x86 và x64 của framework ngay cả khi chúng có cùng số phiên bản.

10

Tôi đã gặp sự cố tương tự khi tôi điền vào một bảng cơ sở dữ liệu với thông tin phụ thuộc vào String.GetHashCode (Không phải ý tưởng tốt nhất) và khi tôi nâng cấp máy chủ tôi đang làm việc trên x64, tôi nhận thấy các giá trị tôi nhận được từ Chuỗi.GetHashCode không phù hợp với những gì đã có trong bảng. Giải pháp của tôi là sử dụng phiên bản GetHashCode của riêng tôi, nó trả về cùng giá trị với String.GetHashCode trên một khung công tác x86.

Dưới đây là đoạn code, đừng quên để biên dịch với "Cho phép mã không an toàn":

/// <summary> 
    /// Similar to String.GetHashCode but returns the same as the x86 version of String.GetHashCode for x64 and x86 frameworks. 
    /// </summary> 
    /// <param name="s"></param> 
    /// <returns></returns> 
    public static unsafe int GetHashCode32(string s) 
    { 
     fixed (char* str = s.ToCharArray()) 
     { 
      char* chPtr = str; 
      int num = 0x15051505; 
      int num2 = num; 
      int* numPtr = (int*)chPtr; 
      for (int i = s.Length; i > 0; i -= 4) 
      { 
       num = (((num << 5) + num) + (num >> 0x1b))^numPtr[0]; 
       if (i <= 2) 
       { 
        break; 
       } 
       num2 = (((num2 << 5) + num2) + (num2 >> 0x1b))^numPtr[1]; 
       numPtr += 2; 
      } 
      return (num + (num2 * 0x5d588b65)); 
     } 
    } 
+1

Tôi đã gặp vấn đề tương tự và đã chuyển phiên bản của bạn sang một phương thức an toàn. https://gist.github.com/gerriten/7542231#file-gethashcode32-net –

-1

tôi sẽ phải nói ... bạn không thể dựa vào nó. Ví dụ nếu tôi chạy file1 thông qua mã băm md5 của C# và C# sao chép cùng một tập tin vào một thư mục mới ... mã băm xuất hiện khác nhau thậm chí khó khăn, nó là cùng một tập tin. Rõ ràng là cùng một phiên bản .net, giống như mọi thứ. Điều duy nhất thay đổi là con đường.

1
/// <summary> 
    /// Default implementation of string.GetHashCode is not consistent on different platforms (x32/x64 which is our case) and frameworks. 
    /// FNV-1a - (Fowler/Noll/Vo) is a fast, consistent, non-cryptographic hash algorithm with good dispersion. (see http://isthe.com/chongo/tech/comp/fnv/#FNV-1a) 
    /// </summary> 
    private static int GetFNV1aHashCode(string str) 
    { 
     if (str == null) 
      return 0; 
     var length = str.Length; 
     // original FNV-1a has 32 bit offset_basis = 2166136261 but length gives a bit better dispersion (2%) for our case where all the strings are equal length, for example: "3EC0FFFF01ECD9C4001B01E2A707" 
     int hash = length; 
     for (int i = 0; i != length; ++i) 
      hash = (hash^str[i]) * 16777619; 
     return hash; 
    } 

Triển khai này có thể chậm hơn so với phiên bản không an toàn được đăng trước đó. Nhưng đơn giản hơn và an toàn hơn.

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