web-dev-qa-db-ja.com

辞書でキーとして使用されるオブジェクトの比較

私のクラス:

public class myClass
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }
}

そして主な例:

Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
myClass first = new myClass();
first.A = 2;
first.B = 3;

myClass second = new myClass();
second.A = 2;
second.B = 3;
second.C = 5;
second.D = 6;

dict.Add(first, new List<string>());

if (dict.ContainsKey(second))
{
    //
    //should come here and update List<string> for first (and only in this example) key 
    //
}
else
{
    //
    //if myFirst object has difference vlues of A or B properties
    //
    dict.Add(second, new List<string>());
}

これを行う方法?

19
Saint

always辞書でAとBのみを比較したい場合は、2つのオプションがあります。 コンストラクタを使用IEqualityComparer<TKey>を実装し、そこに比較ロジックを配置するか、クラスに実装させる IEquateable<T> GetHashCodeとEqualsので、デフォルトの比較子が探している結果を提供します。

1つの状況でAとBのみを比較する場合は、.KeysプロパティとLinq拡張メソッド Contains を使用して、IEqualityComparer<T>を渡すことができるようにする必要があります。ただし、この方法で行うと、辞書を使用することによる速度のメリットが失われるため、辞書は慎重に使用してください。

public class MyClassSpecialComparer : IEqualityComparer<myClass>
{
    public bool Equals (myClass x, myClass y)
    { 
        return x.A == y.A && x.B == y.B 
    }

    public int GetHashCode(myClass x)
    {
       return x.A.GetHashCode() + x.B.GetHashCode();
    }


}


 //Special case for when you only want it to compare this one time
 //NOTE: This will be much slower than a normal lookup.
    var myClassSpecialComparer = new MyClassSpecialComparer();
    Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
    //(Snip)
    if (dict.Keys.Contains(second, myClassSpecialComparer ))
    {
        //
        //should come here and update List<string> for first (and only in this example) key 
        //
    }

 //If you want it to always compare
    Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>(new MyClassSpecialComparer());
30

デフォルトでは、比較はハッシュコードに基づいてオブジェクトをバケットに入れます。 2つのハッシュコードが同じである場合、(Equalsを呼び出すことにより)詳細な比較が実行されます。クラスがGetHashCodeを提供しないか、同等性を実装しない場合、デフォルトのobject.GetHashCodeが使用されます。この場合、クラスに固有の値は値の比較セマンティクスには使用されません。同じ参照のみが見つかります。これが必要ない場合は、GetHashCodeを実装し、等価性を実装してください。

例えば:

public class myClass
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }

    public bool Equals(myClass other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.A == A && other.B == B && other.C == C && other.D == D;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (myClass)) return false;
        return Equals((myClass) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result = A;
            result = (result*397) ^ B;
            result = (result*397) ^ C;
            result = (result*397) ^ D;
            return result;
        }
    }
}
7
Peter Ritchie

MyClassでオーバーライド:

  • GetHashCodeメソッド

  • 等しいメソッド

GetHashCodeメソッドを実装するには、整数プロパティからXOR GetHashCodesを使用します。

オプションでToStringメソッドをオーバーライドし、IEquatableインターフェイスを実装する

4
Regfor