2013-07-12 62 views
9

Tôi đang cố gắng tạo một ứng dụng nhỏ giúp tiết kiệm một số nhân viên Tên, tuổi cũng như tiền lương. Vì vậy, tôi quyết định sử dụng Dictionary để thiết lập mức lương của mỗi nhân viên và tôi đã đưa ra mã màDictionary.ContainsKey Luôn Trả về False

var employeeSalaryDictionary = new Dictionary<Employee, int>(); 
employeeSalaryDictionary.Add(new Employee { Name = "Chuck", Age = 37 }, 1000); 
employeeSalaryDictionary.Add(new Employee { Name = "Norris", Age = 37 }, 2000); 
employeeSalaryDictionary.Add(new Employee { Name = "Rocks", Age = 44 }, 3000); 

Employee employeeToFind = new Employee { Name = "Chuck", Age = 37 }; 
//or even 
Employee employeeToFind = new Employee { Name = "Chuck"}; 

//Always False... 
bool exists = employeeSalaryDictionary.ContainsKey(employeeToFind); 

nhân viên Lớp

public class Employee 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

Tuy nhiên như tôi nhận xét ra hoặc như tiêu đề chủ đề nêu rõ, .ContainsKey luôn trả về tôi False mặc dù tôi đã thử cả hai cách như được hiển thị trong mã.

+1

Bạn nên ghi đè Equals và GetHashCode cho lớp Employee của bạn –

+0

Tôi nghĩ rằng nó có liên quan đến cách đối tượng được so sánh. Vì các đối tượng trong từ điển và trong 'employeeToFind' thực ra là các đối tượng khác nhau - so sánh chúng trả về false –

Trả lời

18

Bạn không sử dụng các nhà xây dựng Dictionary mà mất trong các IEqualityComparer<T> và không có bạn thực hiện bình đẳng tùy chỉnh trên Employee lớp học.

Vì vậy, ngay bây giờ từ điển sẽ so sánh nhân viên theo tham chiếu. Khi bạn new nhân viên, bạn có một tham chiếu khác nhau, mặc dù ví dụ: tên có thể giống nhau.

Có lẽ cách dễ nhất ở đây là triển khai IEqualityComparer<Employee> của riêng bạn, nơi bạn có thể chọn thành viên nào sẽ được sử dụng để so sánh bình đẳng và chuyển nó tới hàm tạo của từ điển.

[EDIT] Như đã hứa, đoạn:

//ReSharper's courtesy 
public sealed class NameAgeEqualityComparer : IEqualityComparer<Employee> 
{ 
    public bool Equals(Employee x, Employee y) 
    { 
     if (ReferenceEquals(x, y)) return true; 
     if (ReferenceEquals(x, null)) return false; 
     if (ReferenceEquals(y, null)) return false; 
     if (x.GetType() != y.GetType()) return false; 
     return string.Equals(x.Name, y.Name) && x.Age == y.Age; 
    } 

    public int GetHashCode(Employee obj) 
    { 
     unchecked 
     { 
      return ((obj.Name != null ? obj.Name.GetHashCode() : 0) * 397)^obj.Age; 
     } 
    } 
} 

Và sau đó:

var employeeSalaryDictionary = new Dictionary<Employee, int>(new NameAgeEqualityComparer()); 
employeeSalaryDictionary.Add(new Employee { Name = "Chuck", Age = 37 }, 1000); 
employeeSalaryDictionary.Add(new Employee { Name = "Norris", Age = 37 }, 2000); 
employeeSalaryDictionary.Add(new Employee { Name = "Rocks", Age = 44 }, 3000); 

Employee employeeToFind = new Employee { Name = "Chuck", Age = 37 }; 
bool exists = employeeSalaryDictionary.ContainsKey(employeeToFind); // true! 

Để hoàn chỉnh, đây là tên chỉ Comparer (còn ReSharper lịch sự):

public sealed class NameEqualityComparer : IEqualityComparer<Employee> 
{ 
     public bool Equals(Employee x, Employee y) 
     { 
      if (ReferenceEquals(x, y)) return true; 
      if (ReferenceEquals(x, null)) return false; 
      if (ReferenceEquals(y, null)) return false; 
      if (x.GetType() != y.GetType()) return false; 
      return string.Equals(x.Name, y.Name); 
     } 

     public int GetHashCode(Employee obj) 
     { 
      return (obj.Name != null ? obj.Name.GetHashCode() : 0); 
     } 
    } 

Nhưng, như bạn nhận thấy, bạn phải quyết định bạn sẽ sử dụng bộ so sánh nào để so sánh khóa khi bạn tạo một từ điển. Điều đó không thể thay đổi sau này ...

+0

Điều đó rất hay nhưng bạn có thể làm cho câu trả lời của mình phong phú hơn bằng cách thêm đoạn mã về cách tôi hoặc bất kỳ ai khác sẽ thấy câu hỏi đó giải quyết vấn đề này theo các mã tôi đã đăng? –

+0

@RuneS Chắc chắn, cho tôi một giây để spool lên Visual Studio;) –

+0

@ RuneS Và thực hiện. –

3

Nhân viên là loại tham chiếu. Khóa từ điển của bạn khi bạn thêm một nhân viên mới sẽ chứa địa chỉ tham chiếu đến đối tượng Employee đó. Nếu bạn tạo một đối tượng người lao động nó có một tài liệu tham khảo khác biệt so với đối tượng nhân viên đầu tiên của bạn, mặc dù chúng chứa cùng một dữ liệu

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