9

従業員の名前、年齢、給与を保存する小さなアプリケーションを作成しようとしています。そこでDictionary、すべての従業員の給与を設定するために使用することにし、そのコードを思いつきました

コード

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

従業員クラス

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

ただし、コメントアウトしたか、トピックのタイトルに記載されているように、コードに示されているように両方の方法を試しましたが、.ContainsKey常に返されます。False

4

2 に答える 2

18

Dictionaryを受け取るコンストラクターを使用しておらず、クラスIEqualityComparer<T>にカスタムの等価性を実装していません。Employee

そのため、現在、辞書は従業員を参照によって比較しています。あなたnewが従業員の場合、たとえば名前が同じであっても、参照先が異なります。

おそらく、ここで最も簡単な方法はIEqualityComparer<Employee>、等価比較に使用するメンバーを選択して辞書のコンストラクターに渡すことができる独自の を実装することです。

[編集] 約束どおり、スニペット:

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

しかし、お気づきのように、ディクショナリを作成するときにキー比較に使用する比較子を決定する必要があります。後から変えられない…

于 2013-07-12T21:54:48.050 に答える
3

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

于 2013-07-12T21:54:34.503 に答える