もう1つのアプローチは、LINQDistinct
拡張メソッドを。と一緒に使用することIEqualityComparer<Foo>
です。比較ツールを実装する必要があります。ただし、後者は再利用可能でテスト可能です。
public class FooDeptCourseEqualityComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
return
x.Dept == y.Dept &&
x.Course.ToLower() == y.Course.ToLower();
}
public int GetHashCode(Foo obj)
{
unchecked {
return 527 + obj.Dept.GetHashCode() * 31 + obj.Course.GetHashCode();
}
}
#region Singleton Pattern
public static readonly FooDeptCourseEqualityComparer Instance =
new FooDeptCourseEqualityComparer();
private FooDeptCourseEqualityComparer() { }
#endregion
}
私の例では、シングルトンパターンを使用しています。クラスには状態情報がないため、使用するたびに新しいインスタンスを作成する必要はありません。
私のコードは値を処理しませんnull
。もちろん、発生する可能性がある場合は、それらを処理する必要があります。
一意の値は次のように返されます
var result = fooList.Distinct(FooDeptCourseEqualityComparer.Instance);
アップデート
コンストラクターでラムダ式を受け入れ、複数の状況で再利用できるジェネリックEqualityComparerクラスを使用することをお勧めします
public class LambdaEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _areEqual;
private Func<T, int> _getHashCode;
public LambdaEqualityComparer(Func<T, T, bool> areEqual,
Func<T, int> getHashCode)
{
_areEqual = areEqual;
_getHashCode = getHashCode;
}
public LambdaEqualityComparer(Func<T, T, bool> areEqual)
: this(areEqual, obj => obj.GetHashCode())
{
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
return _areEqual(x, y);
}
public int GetHashCode(T obj)
{
return _getHashCode(obj);
}
#endregion
}
このように使えます
var comparer = new LambdaEqualityComparer<Foo>(
(x, y) => x.Dept == y.Dept && x.Course == y.Course,
obj => {
unchecked {
return 527 + obj.Dept.GetHashCode() * 31 + obj.Course.GetHashCode();
}
}
);
var result = fooList.Distinct(comparer);
注:内部クラスDistinct
を使用し、内部Set<T>
クラスがハッシュコードを使用するため、ハッシュコードの計算を提供する必要があります。
更新#2
さらに一般的な等式比較子は、比較を自動的に実装し、プロパティアクセサーのリストを受け入れます。ただし、比較の実行方法を制御することはできません。
public class AutoEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, object>[] _propertyAccessors;
public AutoEqualityComparer(params Func<T, object>[] propertyAccessors)
{
_propertyAccessors = propertyAccessors;
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
foreach (var getProp in _propertyAccessors) {
if (!getProp(x).Equals(getProp(y))) {
return false;
}
}
return true;
}
public int GetHashCode(T obj)
{
unchecked {
int hash = 17;
foreach (var getProp in _propertyAccessors) {
hash = hash * 31 + getProp(obj).GetHashCode();
}
return hash;
}
}
#endregion
}
使用法
var comparer = new AutoEqualityComparer<Foo>(foo => foo.Dept,
foo => foo.Course);
var result = fooList.Distinct(comparer);