it-swarm.com.de

So verwenden Sie den IEqualityComparer

Ich habe einige Glocken in meiner Datenbank mit der gleichen Nummer. Ich möchte alle ohne Verdoppelung bekommen. Dann erstelle ich eine Vergleichsklasse, um diese Arbeit zu erledigen, aber die Ausführung der Funktion führt zu einer großen Verzögerung der Funktion ohne eindeutige Verzögerung von 0,6 bis 3,2 Sekunden!

Mache ich es richtig oder muss ich eine andere Methode verwenden? 

       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;
        }

    }
82
Akrem

Kein Wunder, wenn man Ihre GetHashCode-Implementierung betrachtet, die immer denselben Wert zurückgibt. Distinct ist auf eine gute Hash-Funktion angewiesen, um effizient arbeiten zu können.

Bei der Implementierung von Schnittstellen für Klassen müssen Sie deren Dokumentation first lesen, andernfalls wissen Sie nicht, welchen Vertrag Sie ausführen sollen.1

In Ihrem Code besteht die Lösung darin, GetHashCode an Class_reglement.Numf.GetHashCode weiterzuleiten und dort entsprechend zu implementieren.

Abgesehen davon ist Ihre Equals-Methode mit unnötigem Code gefüllt. Es könnte wie folgt umgeschrieben werden (gleiche Semantik, ¼ des Codes, lesbarer):

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

Darüber hinaus ist der Aufruf ToList nicht erforderlich und zeitaufwändig: AddRange akzeptiert alle IEnumerable-Werte, sodass keine Konvertierung in eine List-Anweisung erforderlich ist. AsEnumerable ist auch hier redundant, da die Verarbeitung des Ergebnisses in AddRange dies ohnehin bewirkt.


1 Die Implementierung von Code, ohne zu wissen, was er tatsächlich tut, heißt cargo cult programming . Es ist eine überraschend weit verbreitete Praxis. Es funktioniert grundsätzlich nicht.

161
Konrad Rudolph

Versuchen Sie diesen Code:

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();
    }
}

Ein Beispiel für seine Verwendung wäre

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

Die Einbeziehung Ihrer Vergleichsklasse (oder genauer der AsEnumerable-Aufruf, die Sie verwenden mussten, um sie zum Laufen zu bringen) bedeutete, dass die Sortierlogik nicht mehr vom Datenbankserver, sondern vom Datenbankclient (Ihrer Anwendung) abhing. Dies bedeutet, dass Ihr Client jetzt eine größere Anzahl von Datensätzen abrufen und verarbeiten muss. Dies ist immer weniger effizient als das Durchsuchen der Datenbank, in der die entsprechenden Indizes verwendet werden können.

Sie sollten versuchen, eine Where-Klausel zu entwickeln, die Ihren Anforderungen entspricht. Weitere Informationen finden Sie unter Verwenden eines IEqualityComparer mit einer LINQ to Entities Except-Klausel .

2
Justin

Wenn Sie eine generische Lösung ohne Boxen wünschen:

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);
    }
}

verwendungszweck:

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

Einfach Code mit Implementierung der Validierung GetHashCode und 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;
    }
}

Beispiel: Liste von Class_reglement unterscheidbar nach Numf

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