2011-09-05 45 views
10

Xin chào Tôi có một lớp học với 6 thuộc tính chuỗi. Một đối tượng duy nhất sẽ có các giá trị khác nhau cho ít nhất một trong các trường nàyC# .NET GetHashCode câu hỏi chức năng

Để triển khai hàm GetHashCode của IEqualityComparer, tôi nối tất cả 6 thuộc tính và gọi GetHashCode trên chuỗi kết quả.

tôi đã có những nghi ngờ sau:

  1. Có cần phải gọi GetHashCode trên một giá trị duy nhất?
  2. Thao tác ghép nối trên sáu thuộc tính có làm cho so sánh chậm không?
  3. Tôi có nên sử dụng một số phương pháp tiếp cận khác không?
+0

Are bạn lập kế hoạch so sánh các đối tượng của bạn ở đâu đó chẳng hạn như sắp xếp chúng trong một mảng hoặc một số như vậy?Điều đó sẽ thay đổi thời tiết hay không bạn cần phải thực hiện GetHashCode – mydogisbox

+0

hi mydogisbox, tôi đang sử dụng nó cho phương thức List.Contains và truyền đối tượng so sánh với nó. Tôi đã thực hiện Equals và không biết cách tiếp cận đúng cho GetHashcode – ganeshran

Trả lời

3

GetHashCode không cần trả lại giá trị không bằng nhau cho các đối tượng "không bằng nhau". Nó chỉ cần trả về các giá trị bằng nhau cho các đối tượng bằng nhau (nó cũng phải trả về cùng một giá trị cho tuổi thọ của đối tượng).

Điều này có nghĩa rằng:

  1. Nếu hai vật thể so sánh như bình đẳng với Equals, sau đó họ GetHashCode phải trả về giá trị tương tự.
  2. Nếu một số thuộc tính 6 chuỗi không chỉ đọc đúng, chúng không thể tham gia triển khai GetHashCode.

Nếu bạn không thể thỏa mãn cả hai điểm cùng một lúc, bạn nên đánh giá lại thiết kế của mình vì bất kỳ thứ gì khác sẽ để cánh cửa mở cho lỗi.

Cuối cùng, bạn có thể làm cho GetHashCode nhanh hơn bằng cách gọi GetHashCode trên mỗi 6 chuỗi và sau đó tích hợp tất cả 6 kết quả trong một giá trị bằng cách sử dụng một số thao tác bitwise.

+0

Xin chào Jon, không có thuộc tính nào của tôi là chỉ đọc. Tuy nhiên, tất cả chúng đều có các trình cài đặt riêng mặc dù vậy chỉ có thể được sửa đổi từ hàm tạo. Điều này có ảnh hưởng đến việc sử dụng chúng trong GetHashCode không? – ganeshran

+0

@ganeshran: Sau đó, chúng có hiệu quả chỉ đọc trong suốt thời gian tồn tại của đối tượng (nghĩa là chúng có thể được triển khai với các trường sao lưu 'readonly' nếu bạn muốn), điều đó là đủ. Bạn sẽ ổn thôi. – Jon

+0

@Jon Đọc các điều kiện của bạn để thực hiện 'GetHashCode()', tôi thấy rằng đó là vấn đề với các yêu cầu xung đột. Trong thực tế, bạn chỉ một phần chính xác. Các yêu cầu thực sự cho phương thức 'GetHashCode()' là: 1. Nó sẽ trả về cùng một giá trị cho các đối tượng bằng nhau. 2. Nó sẽ trả về cùng một giá trị cho cùng một đối tượng trong khi nó không được sửa đổi. 3. GetHashCode() phải nhanh. Đồng ý rằng có một số đề xuất khác cho nó. Ví dụ: Để có hiệu suất tốt nhất, hàm băm sẽ tạo phân phối ngẫu nhiên cho tất cả đầu vào. –

3

GetHashCode() phải trả lại mã băm giống nhau cho tất cả các đối tượng trả về true nếu bạn gọi Bằng() trên các đối tượng đó. Điều này có nghĩa là, ví dụ, bạn có thể trả về 0 là mã băm bất kể giá trị của trường là gì. Nhưng điều đó sẽ làm cho đối tượng của bạn rất kém hiệu quả khi được lưu trữ trong các cấu trúc dữ liệu như bảng băm.

Kết hợp các chuỗi là một tùy chọn, nhưng lưu ý rằng bạn có thể ví dụ kết hợp chỉ hai chuỗi cho mã băm (trong khi vẫn so sánh tất cả các chuỗi bằng bằng nhau!).

Bạn cũng có thể kết hợp băm của sáu chuỗi riêng biệt, thay vì tính một băm đơn cho một chuỗi kết hợp. Xem ví dụ Quick and Simple Hash Code Combinations

Tôi không chắc chắn điều này sẽ nhanh hơn đáng kể so với ghép chuỗi không.

+0

Cảm ơn Anders, tôi đang sử dụng nó chỉ cho Chứa so sánh phương pháp. Nếu tôi kết hợp chỉ có hai chuỗi cho hashcode, wouldnt hashcodes được giống nhau nếu hai giá trị trong các đối tượng là như nhau? Điều này sẽ làm rối loạn sự so sánh, hay liệu GetHashCode không ảnh hưởng đến sự so sánh, và chỉ ảnh hưởng đến hiệu suất – ganeshran

+1

Những người khác đã làm được điều này, nhưng tôi muốn giải quyết nó theo một cách khác vì dường như trực giác của bạn bị mắc kẹt. Quan sát rằng GetHashCode() trả về một int, có thể chỉ nhận được 2^32 giá trị khác nhau. Đối tượng của bạn, bao gồm 6 chuỗi có chiều dài tùy ý, rõ ràng có thể chiếm một số lượng lớn các giá trị. Qua ví dụ này, chúng ta có thể dễ dàng thấy rằng GetHashCode() không thể là một giá trị duy nhất cho tất cả các giá trị có thể có của đối tượng của bạn. Nó chỉ phải thỏa mãn thuộc tính này: "nếu a.Equals (b) thì a.GetHashCode() == b.GetHashCode()"; và chú ý rằng "nếu" KHÔNG đi cả hai chiều. –

+1

Cân nhắc thực tế cho GetHashCode() là nó "tốt" và "nhanh". Để làm cho nó "nhanh" tôi sẽ cố gắng tránh tất cả các cấp phát bộ nhớ và sao chép chuỗi; để làm cho nó "tốt" là một chủ đề của một số sắc thái nhưng trong thực tế nó suffices để swizzle với nhau các GetHashCode() giá trị của các đối tượng phụ như @ Jon cho thấy. Tôi sẽ đăng đề xuất của ReSharper là "câu trả lời" để tôi có thể nhận được định dạng mã. –

4

Nếu lĩnh vực chuỗi của bạn được đặt tên af và được biết đến không phải là null, đây là đề nghị ReSharper cho GetHashCode của bạn()

public override int GetHashCode() { 
    unchecked { 
    int result=a.GetHashCode(); 
    result=(result*397)^b.GetHashCode(); 
    result=(result*397)^c.GetHashCode(); 
    result=(result*397)^d.GetHashCode(); 
    result=(result*397)^e.GetHashCode(); 
    result=(result*397)^f.GetHashCode(); 
    return result; 
    } 
} 
+0

Cảm ơn, tôi sẽ sử dụng mã này. – ganeshran

+0

Xem câu trả lời của tôi ở đây: http://stackoverflow.com/a/34006336/1911540 –