2008-09-16 3 views

答えて

2

これはMSDNは(非ジェネリック)されたIEqualityComparerについて言いたいことです:

このインタフェースは、コレクションのためにカスタマイズされた等価比較を実装することができます。つまり、独自の等価定義を作成し、この定義をIEqualityComparerインタフェースを受け入れるコレクション型とともに使用することができます。 .NET Frameworkでは、HashtableNameValueCollection、およびOrderedDictionaryのコンストラクターがこのインターフェイスを受け入れます。

このインターフェイスは、等価比較のみをサポートしています。並べ替えと並べ替えの比較のカスタマイズは、IComparerインターフェイスによって提供されます。

このインターフェイスの汎用バージョンは同じ機能を実行しますが、Dictionary<(Of <(TKey, TValue>)>)コレクションに使用されているようです。

このインターフェイスを自分の目的で使用することに関するベストプラクティスです。上記の.NET Frameworkコレクションと同様の機能を持ち、独自のコレクションに同じ機能を追加したいクラスを派生または実装するときに使用することをお勧めします。これにより、.NETフレームワークがどのようにインターフェイスを使用するかが一貫しています。

つまり、カスタムコレクションを開発していて、多くのLINQやコレクション関連のメソッド(Sortなど)で使用されている等価性を消費者が制御できるようにする場合は、このインターフェイスの使用をサポートします。

1

私は、特定のアルゴリズムに対して異なる等価ルールをプラグインする必要があるときに最適な使い方と言います。多くのソートアルゴリズムはIComparer<T>を受け入れる可能性があるのと同じように、発見アルゴリズムはIEqualityComparer<T>

1

を受け入れるかもしれないリストは、このインタフェースの多くを使用していますので、あなたはa.Substract(b)又はこれらの素敵な機能の他に言うことができます。

覚えておいて欲しいのは、オブジェクトが同じハッシュコードを返さない場合は、Equalsは呼び出されません。

5

私は以下のことを行いました。実際のベストプラクティスであるかどうかはわかりませんが、うまくいきました。 :)

public class GenericEqualityComparer<T> : IEqualityComparer<T> 
{ 
    private Func<T, T, Boolean> _comparer; 
    private Func<T, int> _hashCodeEvaluator; 
    public GenericEqualityComparer(Func<T, T, Boolean> comparer) 
    { 
     _comparer = comparer; 
    } 

    public GenericEqualityComparer(Func<T, T, Boolean> comparer, Func<T, int> hashCodeEvaluator) 
    { 
     _comparer = comparer; 
     _hashCodeEvaluator = hashCodeEvaluator; 
    } 

    #region IEqualityComparer<T> Members 

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

    public int GetHashCode(T obj) 
    { 
     if(obj == null) { 
      throw new ArgumentNullException("obj"); 
     } 
     if(_hashCodeEvaluator == null) { 
      return 0; 
     } 
     return _hashCodeEvaluator(obj); 
    } 

    #endregion 
} 

あなたのコレクションで使用できます。

var comparer = new GenericEqualityComparer<ShopByProduct>((x, y) => x.ProductId == y.ProductId); 
var current = SelectAll().Where(p => p.ShopByGroup == group).ToList(); 
var toDelete = current.Except(products, comparer); 
var toAdd = products.Except(current, comparer); 

あなたは、カスタムメソッドGetHashCode()機能をサポートする代替計算を行うためのラムダを提供するために、代替コンストラクタを使用する必要がある場合:

var comparer = new GenericEqualityComparer<ShopByProduct>(
     (x, y) => { return x.ProductId == y.ProductId; }, 
     (x) => { return x.Product.GetHashCode()} 
); 

私はこのことができます願っています。 =)

+1

問題: 'obj.GetHashCode()'が意味をなさないと考えることはできません。私のポストのリンクを参照してください:http://stackoverflow.com/questions/74032/whats-the-recommended-best-practice-for-using-iequalitycomparert/4679491#4679491 –

+1

**このデフォルトの 'obj .GetHashCode() 'フォールバック。例comparer: '(s1、s2)=> s1.ToLower()。Equals(s2.ToLower())'は、デフォルトの 'string.GetHashCode()'がfalseを返す場合に 'true'を返します。 – ulrichb

11

IEqualityComparer<T>の使用を検討する場合は、代わりにIEquatable<T>を実装するクラスを作成できるかどうか考えてください。 Productを常にIDで比較する必要がある場合は、デフォルトの比較元を使用できるようにIDを定義してください。

、請求、カスタムの比較子をお勧めします理由のいくつか残っています:クラスのインスタンスが等しいと考えることができる複数の方法がある場合は

  1. が。これの最も良い例は、フレームワークがStringComparerに6つの異なる比較文字を提供する文字列です。
  2. クラスが、IEquatable<T>として定義できないように定義されている場合。これには、コンパイラによって生成された他のクラスやクラスによって定義されたクラスが含まれます(特に匿名型、デフォルトではプロパティーとの比較が使用されます)。

比較器が必要な場合は、一般化された比較器(DMenTの回答を参照)を使用できますが、そのロジックを再利用する必要がある場合は専用クラスにカプセル化する必要があります。

class ProductByIdComparer : GenericEqualityComparer<ShopByProduct> 
{ 
    public ProductByIdComparer() 
     : base((x, y) => x.ProductId == y.ProductId, z => z.ProductId) 
    { } 
} 

可能であれば、比較者を利用する必要があります。たとえば、辞書のキーとして使用されるすべての文字列(アプリ全体に渡るロジック)にToLower()を呼び出すのではなく、大文字小文字を区別しないStringComparerを使用するように辞書を宣言する必要があります。比較演算子を受け入れるLINQ演算子も同じです。しかし、やはり、外部から定義されるのではなく、クラスに固有でなければならない等価な動作であるかどうかを常に検討してください。

関連する問題