2009-09-10 23 views
12

Tôi đã sử dụng Từ điển (TKey, TValue) cho nhiều mục đích. Nhưng tôi đã không gặp phải bất kỳ kịch bản để thực hiện GetHashCode() mà tôi tin là bởi vì các phím của tôi là các loại chính như int và chuỗi. Tôi tò mò muốn biết các kịch bản (ví dụ thế giới thực) khi người ta nên sử dụng một đối tượng tùy chỉnh cho khóa và do đó thực hiện các phương thức GetHashCode() Equals() v.v.Khi nào chúng ta thực hiện GetHashCode() cho một từ điển?

Và, sử dụng một đối tượng tùy chỉnh cho khóa cần thực hiện chức năng?

+0

có thể trùng lặp của [Tại sao điều quan trọng là ghi đè GetHashCode khi phương thức Equals bị ghi đè?] (Http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when- equals-is-overridden) – nawfal

Trả lời

13

Bạn nên ghi đè EqualsGetHashCode bất cứ khi nào mặc định Object.Equals (các thử nghiệm cho bình đẳng tham chiếu) sẽ không đủ. Điều này xảy ra, ví dụ, khi loại khóa của bạn là một loại tùy chỉnh và bạn muốn hai khóa được coi là bằng nhau ngay cả trong trường hợp chúng không phải là cùng một thể hiện của loại tùy chỉnh.

Ví dụ, nếu chìa khóa của bạn cũng đơn giản như

class Point { 
    public int X { get; set; } 
    public int Y { get; set; } 
} 

và bạn muốn hai Point s hai được coi là tương đương nếu họ X s đều bình đẳng và họ Y s đều bình đẳng sau đó bạn sẽ cần phải ghi đè EqualsGetHashCode.

+0

liên quan đến một từ điển , những gì hiện bằng và GetHashCode cần phải được nếu 1) Tôi chỉnh sửa đối tượng tại chỗ và trao đổi 'point.X' cho' point.Y'? Liệu giá trị có phải được loại bỏ và thêm vào từ điển? – LamonteCristo

2

Một ví dụ là khi bạn cần tạo khóa tổng hợp (đó là khóa bao gồm nhiều hơn một phần dữ liệu đó). Khóa tổng hợp đó sẽ là loại tùy chỉnh cần phải ghi đè các phương thức đó. Ví dụ: giả sử bạn có một bộ nhớ cache trong bộ nhớ địa chỉ và bạn muốn kiểm tra xem địa chỉ có trong bộ nhớ cache để lưu một chuyến đi đắt tiền đến cơ sở dữ liệu để truy xuất nó hay không. Cũng hãy nói rằng các địa chỉ là duy nhất trong các trường số đường phố 1mã zip của chúng tôi. Bạn sẽ thực hiện bộ nhớ cache của bạn với một cái gì đó như thế này:

class AddressCacheKey 
{ 
    public String StreetOne { get; set; } 
    public String ZipCode { get; set; } 

    // overrides for Equals and GetHashCode 
} 

static Dictionary<AddressCacheKey,Address> cache; 

Kể từ loại AddressCacheKey của bạn sẽ ghi đè các phương pháp EqualsGetHashCode họ sẽ là một ứng cử viên tốt cho một chìa khóa trong từ điển và bạn sẽ có thể xác định xem bạn có cần phải thực hiện một chuyến đi đến cơ sở dữ liệu để lấy một bản ghi dựa trên nhiều hơn một phần dữ liệu hay không.

1

Bạn có hai câu hỏi tại đây.

  1. Khi nào thì bạn cần phải thực hiện GetHashCode()
  2. Bạn có bao giờ sử dụng một đối tượng cho một chìa khóa từ điển.

Cho phép bắt đầu bằng 1. Nếu bạn đang viết một lớp có thể được người khác sử dụng, bạn sẽ muốn xác định GetHashCode() và Equals(), khi tham chiếu Bằng() là không đủ. Nếu bạn không dự định sử dụng nó trong từ điển, và đó là cách sử dụng của riêng bạn, thì tôi không thấy lý do gì để bỏ qua GetHashCode() v.v.

Đối với 2), bạn nên sử dụng một đối tượng bất cứ khi nào bạn có nhu cầu để có một thời gian tra cứu liên tục từ một đối tượng đến một số loại khác. Kể từ khi GetHashCode() trả về một giá trị số, và các bộ sưu tập lưu trữ các tham chiếu, không có hình phạt cho việc sử dụng một đối tượng trên một Int hoặc một chuỗi (nhớ một chuỗi là một đối tượng).

9

Chỉ cần để làm cho nó rõ ràng: Có một điều quan trọng về Dictionary<TKey, TValue>GetHashCode(): từ điển sử dụng GetHashCode để xác định xem hai phím đều bình đẳng Ví dụ: nếu <TKey> là loại tùy chỉnh, bạn nên quan tâm đến việc thực hiện GetHashCode() cẩn thận. Như Andrew Hare đã chỉ ra điều này là dễ dàng, nếu bạn có một loại đơn giản để xác định đối tượng tùy chỉnh của bạn một cách rõ ràng. Trong trường hợp bạn có một số nhận dạng kết hợp, nó sẽ phức tạp hơn một chút.

Ví dụ: xem xét một số phức là TKey. Một số phức được xác định bởi số thực và phần ảo của nó. Cả hai loại đều đơn giản, ví dụ: double. Nhưng làm thế nào bạn sẽ xác định được nếu hai số phức bằng nhau? Bạn triển khai GetHashode() cho loại phức hợp tùy chỉnh của mình và kết hợp cả hai phần xác định.

Bạn tìm đọc thêm sau trên here.

CẬP NHẬT

Dựa trên nhận xét Ergwun của tôi đã kiểm tra hành vi của Dictionary<TKey, TValue>.Add với sự tôn trọng đặc biệt để TKey 's thực hiện Equals(object)GetHashCode(). Tôi phải thú nhận rằng tôi đã khá ngạc nhiên bởi kết quả.

Với hai đối tượng k1k2 loại TKey, hai đối tượng tùy ý v1v2 loại TValue, và một từ điển rỗng d loại Dictionary<TKey, TValue>, đây là những gì sẽ xảy ra khi thêm v1 với phím k1-d đầu tiên và v2 với phím k2 thứ hai (tùy thuộc vào việc thực hiện các TKey.Equals(object)TKey.GetHashCode()):

k1.Equals(k2) k1.GetHashCode() == k2.GetHashCode() d.Add(k2, v2) 
false   false         ok 
false   true         ok 
true   false         ok 
true   true         System.ArgumentException 

Côn clusion: Tôi đã sai lầm như ban đầu tôi nghĩ trường hợp thứ hai (trong đó Equals trả về false nhưng cả hai đối tượng chính có cùng mã băm) sẽ tăng ArgumentException. Nhưng khi trường hợp thứ ba hiển thị từ điển theo một số cách, hãy sử dụng GetHashCode(). Dù sao nó có vẻ là lời khuyên tốt rằng hai đối tượng có cùng loại và bằng nhau phải trả lại mã băm giống nhau để đảm bảo rằng các trường hợp Dictionary<TKey, TValue> hoạt động chính xác.

+9

-1 Từ điển KHÔNG sử dụng 'GetHashCode()' để xác định xem hai khóa có bằng nhau hay không. Tức là, một từ điển có thể chứa các mục riêng biệt có khóa có cùng mã băm. Từ điển có thể kém hiệu quả hơn nhưng nó vẫn hoạt động. – Ergwun

+2

+1 Để cập nhật :) – Ergwun

+0

Có, bạn nên đảm bảo rằng các đối tượng bằng nhau trả về cùng mã băm (xem http://msdn.microsoft.com/en-us/library/ms182358.aspx). – Ergwun

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