カスタムオブジェクトの強力に型指定されたリスト、MyObjectがあります。MyObjectには、プロパティIDとその他のプロパティがあります。
MyObjectのIDが一意として定義しているとしましょう。新しいMyObjectをコレクションに追加する前に、コレクションにIdが1のMyObjectオブジェクトがまだないかどうかを確認します。
if(!List.Contains(myObj))を使用したいのですが、MyObjectの1つまたは2つのプロパティのみがそれを一意として定義するという事実をどのように強制しますか?
IComparableを使用できますか?または、Equalsメソッドをオーバーライドするだけでよいのですが、最初に何かを継承する必要がありますか?
ありがとう
List<T>.Contains
はEqualityComparer<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);
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);
LINQを使用すると、これを非常に簡単に行うことができます。
var result = MyCollection.Any(p=>p.myId == Id);
if(result)
{
//something
}
EqualsとGetHashCodeをオーバーライドし、IEqualityComparer<MyObject>
およびContains
呼び出しで使用するか、Any
などの拡張メソッドを使用します
if (!myList.Any(obj => obj.Property == obj2.Property && obj.Property2 == obj2.Property2))
myList.Add(obj2);
IEquatable<T>
を使用できます。これをクラスに実装し、Equalsに渡されたTがthis.Idと同じIDを持っているかどうかを確認します。これは辞書のキーをチェックするのに役立つと確信していますが、コレクションには使用していません。
最初に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();
このようにして、クラスを変更せずに等価性を計算する方法を定義できます。コードを変更できないため、サードパーティライブラリのオブジェクトの処理にも使用できます。