web-dev-qa-db-ja.com

IEqualityComparerの使用方法

データベースには同じ番号の鐘がいくつかあります。重複することなくそれらすべてを取得したいです。次に、この作業を行うために比較クラスを作成しますが、関数の実行は、0.6秒から3.2秒まで、明確に関数から大きな遅延を生じます!

私はそれを正しくやっていますか、別の方法を使用する必要がありますか?

       reg.AddRange((from a in this.dataContext.reglements
                     join b in this.dataContext.Clients on a.Id_client equals b.Id
                     where a.date_v <= datefin && a.date_v >= datedeb
                     where a.Id_client == b.Id
                     orderby a.date_v descending 
                     select new Class_reglement
                     {
                         nom = b.Nom,
                         code = b.code,
                         Numf = a.Numf,
                     }).AsEnumerable().Distinct(new Compare()).ToList());


    class Compare : IEqualityComparer<Class_reglement>
    {
        public bool Equals(Class_reglement x, Class_reglement y)
        {
            if (x.Numf == y.Numf)
            {
                return true;
            }
            else { return false; }
        }
        public int GetHashCode(Class_reglement codeh)
        {
            return 0;
        }

    }
89
Akrem

常に同じ値を返すGetHashCode実装を検討するのも当然です。 Distinctは、効率的に機能するために適切なハッシュ関数に依存しています。

クラスのインターフェースを実装する場合、 documentation firstを読む必要があります。実装する。1

コード内での解決策は、GetHashCodeClass_reglement.Numf.GetHashCodeに転送し、そこで適切に実装することです。

それとは別に、Equalsメソッドには不要なコードがいっぱいです。次のように書き換えることができます(同じセマンティクス、コードの1/4、より読みやすい):

public bool Equals(Class_reglement x, Class_reglement y)
{
    return x.Numf == y.Numf;
}

さらに、ToList呼び出しは不要で時間がかかります。AddRangeIEnumerableを受け入れるため、Listへの変換は必要ありません。 AsEnumerableは結果をAddRangeで処理するととにかくこれが発生するため、ここではalsoも冗長です。


1 実際に何をするのか知らずにコードを実装することを cargo cult programming と呼びます。それは驚くほど広く行われている習慣です。基本的に機能しません。

161
Konrad Rudolph

このコードを試してください:

public class GenericCompare<T> : IEqualityComparer<T> where T : class
{
    private Func<T, object> _expr { get; set; }
    public GenericCompare(Func<T, object> expr)
    {
        this._expr = expr;
    }
    public bool Equals(T x, T y)
    {
        var first = _expr.Invoke(x);
        var sec = _expr.Invoke(y);
        if (first != null && first.Equals(sec))
            return true;
        else
            return false;
    }
    public int GetHashCode(T obj)
    {
        return obj.GetHashCode();
    }
}

その使用例は

collection = collection
    .Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
    .ToList(); 
43
suneelsarraf

GetHashCodeおよびNULL検証を実装したコードのみ:

public class Class_reglementComparer : IEqualityComparer<Class_reglement>
{
    public bool Equals(Class_reglement x, Class_reglement y)
    {
        if (x is null || y is null))
            return false;

        return x.Numf == y.Numf;
    }

    public int GetHashCode(Class_reglement product)
    {
        //Check whether the object is null 
        if (product is null) return 0;

        //Get hash code for the Numf field if it is not null. 
        int hashNumf = product.hashNumf == null ? 0 : product.hashNumf.GetHashCode();

        return hashNumf;
    }
}

例:Class_reglementのリストNumf

List<Class_reglement> items = items.Distinct(new Class_reglementComparer());
2
Shahar Shokrani

比較クラス(または、より具体的には、それを機能させるために使用する必要があるAsEnumerable呼び出し)を含めることは、ソートロジックがデータベースサーバーに基づくものからデータベースクライアント(アプリケーション)にあることを意味します。これは、クライアントが大量のレコードを取得して処理する必要があることを意味し、適切なインデックスを使用できるデータベースでルックアップを実行するよりも常に効率が低下します。

代わりに、要件を満たすwhere句の開発を試みる必要があります。詳細については、 LINQ to Entities Except句でのIEqualityComparerの使用 を参照してください。

2
Justin

ボクシングなしの一般的なソリューションが必要な場合:

public class KeyBasedEqualityComparer<T, TKey> : IEqualityComparer<T>
{
    private readonly Func<T, TKey> _keyGetter;

    public KeyBasedEqualityComparer(Func<T, TKey> keyGetter)
    {
        _keyGetter = keyGetter;
    }

    public bool Equals(T x, T y)
    {
        return EqualityComparer<TKey>.Default.Equals(_keyGetter(x), _keyGetter(y));
    }

    public int GetHashCode(T obj)
    {
        TKey key = _keyGetter(obj);

        return key == null ? 0 : key.GetHashCode();
    }
}

public static class KeyBasedEqualityComparer<T>
{
    public static KeyBasedEqualityComparer<T, TKey> Create<TKey>(Func<T, TKey> keyGetter)
    {
        return new KeyBasedEqualityComparer<T, TKey>(keyGetter);
    }
}

使用法:

KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf)
1
user764754