2013-07-12 8 views
9

まあ、私はいくつかの従業員名前、年齢と給与を保存する小さなアプリケーションを作成しようとしています。だから私は、すべての従業員の給与を設定するために、Dictionaryを使用することを決めたと私はアウトかのようにコメントとして、私はそのコードDictionary.ContainsKey常に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); 

Employeeクラス

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

しかしを思い付いトピックのタイトルの状態は、.ContainsKeyは常にFalseを返しますが、コードに示すように両方の方法を試しました。

+1

EmployeeクラスのEqualsとGetHashCodeをオーバーライドする必要があります。 –

+0

オブジェクトが比較される方法と関係があると思います。辞書内のオブジェクトと 'employeeToFind'内のオブジェクトは実際には異なるオブジェクトなので、それらを比較すると偽が返されます –

答えて

18

を取り入れていないDictionaryコンストラクタを使用しておらず、 Employeeクラス。

だから、辞書は参照によって従業員を比較しています。 newの従業員はの別のの参照を持っています。名前は同じかもしれません。

ここで最も簡単な方法は、自分でIEqualityComparer<Employee>を実装することです。ここでは、どのメンバを等価比較に使用するかを選んで辞書のコンストラクタに渡すことができます。

[EDIT]約束通り、スニペット:

//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; 
     } 
    } 
} 

そして:完全性については

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! 

、ここでは名前のみの比較演算(もReSharperのの礼儀)です:

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); 
     } 
    } 

しかし、あなたが気づいたように、辞書を作成するときに、どの比較者をキー比較に使用するかを決定する必要があります。後で変更することはできません。

+0

それはいいですが、私は誰か他の誰がその質問を見ることができるかのコードスニペットを追加することで、私が掲示したコードによると、この問題は? –

+0

@ LouneS確かに、Visual Studioをスプールするための秒を与えてください;) –

+0

@RuneSそして完了。 –

3

従業員は参照タイプです。新しい従業員を追加するときの辞書キーには、そのEmployeeオブジェクトへの参照アドレスが含まれます。他の従業員オブジェクトを作成すると、同じデータが含まれていても、最初の従業員オブジェクトとの差分参照があります

関連する問題