web-dev-qa-db-ja.com

Collection.Contains()は、既存のオブジェクトをチェックするために何を使用しますか?

カスタムオブジェクトの強力に型指定されたリスト、MyObjectがあります。MyObjectには、プロパティIDとその他のプロパティがあります。
MyObjectのIDが一意として定義しているとしましょう。新しいMyObjectをコレクションに追加する前に、コレクションにIdが1のMyObjectオブジェクトがまだないかどうかを確認します。
if(!List.Contains(myObj))を使用したいのですが、MyObjectの1つまたは2つのプロパティのみがそれを一意として定義するという事実をどのように強制しますか?
IComparableを使用できますか?または、Equalsメソッドをオーバーライドするだけでよいのですが、最初に何かを継承する必要がありますか?



ありがとう

47
topwik

List<T>.ContainsEqualityComparer<T>.Defaultを使用し、型が実装する場合はIEquatable<T>を使用し、そうでない場合はobject.Equalsを使用します。

IEquatable<T>を実装することもできますが、object.Equalsをオーバーライドすることをお勧めします。veryGetHashCode()をオーバーライドすることをお勧めします:

public class SomeIDdClass : IEquatable<SomeIDdClass>
{
    private readonly int _id;
    public SomeIDdClass(int id)
    {
        _id = id;
    }
    public int Id
    {
        get { return _id; }
    }
    public bool Equals(SomeIDdClass other)
    {
        return null != other && _id == other._id;
    }
    public override bool Equals(object obj)
    {
        return Equals(obj as SomeIDdClass);
    }
    public override int GetHashCode()
    {
        return _id;
    }
}

ハッシュコードは、同等性の基準に関連していることに注意してください。これは非常に重要です。

これにより、同じIDを持つことで定義された平等が有用な他の場合にも適用できます。リストにそのようなオブジェクトがあるかどうかを確認する必要がある場合は、おそらく次のことをお勧めします。

return someList.Any(item => item.Id == cmpItem.Id);
48
Jon Hanna

List<T>は、EqualityComparer<T>.Defaultによって返される比較演算子を使用し、そのための documentation に従います。

Defaultプロパティは、タイプTがSystem.IEquatable(Of T)インターフェイスを実装しているかどうかをチェックし、実装している場合は、その実装を使用するEqualityComparer(Of T)を返します。それ以外の場合、Tが提供するObject.EqualsおよびObject.GetHashCodeのオーバーライドを使用するEqualityComparer(Of T)を返します。

したがって、カスタムクラスにIEquatable<T>を実装するか、Equals(およびGetHashCode)メソッドをオーバーライドして、必要なプロパティによる比較を行うことができます。または、linqを使用できます。

bool contains = list.Any(i => i.Id == obj.Id);
28
Lee

LINQを使用すると、これを非常に簡単に行うことができます。

var result = MyCollection.Any(p=>p.myId == Id);
if(result)
{
     //something
}
6
Robaticus

EqualsとGetHashCodeをオーバーライドし、IEqualityComparer<MyObject>およびContains呼び出しで使用するか、Anyなどの拡張メソッドを使用します

if (!myList.Any(obj => obj.Property == obj2.Property && obj.Property2 == obj2.Property2))
   myList.Add(obj2);
2
Anthony Pegram

IEquatable<T>を使用できます。これをクラスに実装し、Equalsに渡されたTがthis.Idと同じIDを持っているかどうかを確認します。これは辞書のキーをチェックするのに役立つと確信していますが、コレクションには使用していません。

0
davisoa

最初にIEqualityComparerでヘルパークラスを定義します。

public class MyEqualityComparer<T> : IEqualityComparer<T>
{
    Func<T, int> _hashDelegate;

    public MyEqualityComparer(Func<T, int> hashDelegate)
    {
        _hashDelegate = hashDelegate;
    }

    public bool Equals(T x, T y)
    {
        return _hashDelegate(x) == _hashDelegate(y);
    }

    public int GetHashCode(T obj)
    {
        return _hashDelegate(obj);
    }
}

次に、コードでコンパレータを定義して使用します。

var myComparer = new MyEqualityComparer<MyObject>(delegate(MyObject obj){
    return obj.ID;
});

var result = collection
   .Where(f => anotherCollection.Contains(f.First, myComparer))
   .ToArray();

このようにして、クラスを変更せずに等価性を計算する方法を定義できます。コードを変更できないため、サードパーティライブラリのオブジェクトの処理にも使用できます。

0
Tomas Kubes