Wann wird IComparable <T> Vs. IComparer <T>

101

Ich versuche herauszufinden, welche dieser Schnittstellen ich implementieren muss. Beide machen im Wesentlichen dasselbe. Wann würde ich eins über das andere verwenden?

Micah
quelle
Große Beispiele und Erläuterungen finden Sie hier: support.microsoft.com/nl-nl/help/320727/...
Jan

Antworten:

96

Nun, sie sind nicht ganz dasselbe wie IComparer<T>bei einem Typ, der zwei verschiedene Objekte vergleichen kann, während IComparable<T>sie bei Typen implementiert sind, die sich mit anderen Instanzen desselben Typs vergleichen können.

Ich neige dazu, IComparable<T>Zeiten zu verwenden, in denen ich wissen muss, wie sich eine andere Instanz auf eine Instanz bezieht this. IComparer<T>ist nützlich zum Sortieren von Sammlungen, da die IComparer<T>Stände außerhalb des Vergleichs liegen.

Andrew Hare
quelle
9
Mit IComparer <T> können Sie auch eine Klasse für jeden gewünschten Sortiertyp festlegen. Beispiel; PersonLastFirstNameComparer, PersonFirstLastNameComparer oder PersonAgeComparer.
Eric Schneider
Gibt es eine einfache Möglichkeit, sich an sie zu erinnern? Ich muss es jedes Mal nachschlagen.
Amadib
59
@ Amadib denke, IComparablewie ich vergleichbar bin . was bedeutet, dass ich mit etwas anderem verglichen werden kann. Und IComparerwenn ich ein Vergleicher bin, vergleiche ich einfach, was bedeutet, dass ich einige Dinge vergleiche.
Nawfal
@newfal Du hättest das als Antwort setzen sollen. Ich denke, das ist die beste Erklärung hier.
Gene S
42

Verwenden Sie diese Option, IComparable<T>wenn die Klasse einen intrinsischen Vergleich aufweist.

Verwenden IComparer<T>Sie diese Option, wenn Sie eine andere Vergleichsmethode als den intrinsischen Vergleich der Klasse wünschen, sofern diese vorhanden ist.

Yfeldblum
quelle
28

Es hängt von der Entität ab. Wenn Sie beispielsweise für eine Klasse wie "Student" folgen, ist es sinnvoll, IComparable basierend auf Name zu verwenden.

class Student : IComparable 
{
    public string Name { get; set; }
    public int MathScore { get; set; }
    public int EnglishScore { get; set; }

    public int TotalScore 
    {
        get
        {
            return this.MathScore + this.EnglishScore; 
        }
    }

    public int CompareTo(object obj)
    {
        return CompareTo(obj as Student);  
    }

    public int CompareTo(Student other)
    {
        if (other == null)
        {
            return 1;
        }
        return this.Name.CompareTo(other.Name);  
    }
}

Aber wenn ein Lehrer 'A' Schüler basierend auf MathScore vergleichen möchte und Lehrer 'B' Schüler basierend auf EnglishScore vergleichen möchte. Es wird empfohlen, IComparer separat zu implementieren. (Eher wie ein Strategiemuster)

class CompareByMathScore : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        if (x.MathScore > y.MathScore)
          return 1;
        if (x.MathScore < y.MathScore)
          return -1;
        else
          return 0;
    }
}
Ajay Bhosale
quelle
Machen Sie die Compare-Methode für eine einfache Verwendung statisch .
Jan
9

Es hängt alles davon ab, ob Ihr Typ veränderlich ist oder nicht. Sie sollten nur IComparable auf nicht-veränderbare Typen implementieren. Beachten Sie, dass Sie bei der Implementierung von IComparable Equals zusammen mit den Operatoren == ,! =, <und> überschreiben müssen (siehe Warnung CA1036 zur Codeanalyse).

Zitat von Dave G aus diesem Blog-Beitrag :

Die richtige Antwort ist jedoch, IComparer anstelle von IComparable zu implementieren, wenn Ihre Objekte veränderbar sind, und bei Bedarf eine Instanz des IComparer an Sortierfunktionen zu übergeben.

Da der IComparer nur ein Einwegobjekt ist, das zu diesem Zeitpunkt zum Sortieren verwendet wird, kann Ihr Objekt jede gewünschte veränderbare Semantik haben. Darüber hinaus ist die Verwendung von Equals, GetHashCode oder == nicht erforderlich oder wird sogar nicht empfohlen. Sie können es beliebig definieren.

Schließlich können Sie mehrere IComparer für Ihren Typ definieren, um nach verschiedenen Feldern oder mit verschiedenen Regeln zu sortieren. Dies ist viel flexibler, als an einer Definition festzuhalten.

Kurz gesagt: Verwenden Sie IComparable für Werttypen und IComparer für Referenztypen.

Mr. Bungle
quelle
6

Einfache Erklärung über eine Geschichte

High School Basketball. Es ist eine Schulhofauswahl für die Teams. Ich möchte die größten / besten / schnellsten Leute in meinem Team haben. Was mache ich?

IComparer-Schnittstelle - Vergleichen Sie zwei Personen, die unterschiedliche Personen sind

  • Dies erlaubt mir, zwei beliebige Typen zu vergleichen, die in einer Reihe stehen ......... das war's im Grunde. Fred vs John .......... ich werfe sie in eine konkrete Klasse, die die Schnittstelle implementiert. Compare(Fred, John)und es spuckt aus, wer besser ist.

Was ist mit IComparable? - Vergleichen Sie sich mit jemand anderem

Warst du kürzlich auf FB? Sie sehen andere Leute, die coole Dinge tun: um die Welt reisen, Erfindungen kreieren, während ich etwas mache, das nicht ganz so cool ist - nun, wir nutzen die IComparable-Oberfläche.

  • Wir vergleichen die aktuelle Instanz (Sie selbst) mit einem anderen Objekt (jemand anderem), das vom gleichen Typ (Person) ist.

Was ist mit der Vergleichsklasse?

Die Comparer-Klasse ist eine abstrakte Basisklasse, die die IComparer-Schnittstelle implementiert. Sie sollten von dieser Klasse ableiten, um eine konkrete Implementierung zu erhalten. Microsoft empfiehlt jedoch, dass Sie die Comparer-Klasse verwenden, anstatt die IComparer-Schnittstelle zu implementieren:

Es wird empfohlen, dass Sie von der Comparer-Klasse ableiten, anstatt die IComparer-Schnittstelle zu implementieren, da die Comparer-Klasse eine explizite Schnittstellenimplementierung der IComparer.Compare-Methode und der Default-Eigenschaft bereitstellt, die den Standardvergleicher für das Objekt abruft.

Zusammenfassung

  • IComparer - richte zwei Dinge aus und vergleiche.
  • IComparable - vergleiche dich mit anderen auf FB.

Hoffe, die Geschichten helfen dir, dich zu erinnern.

BKSpurgeon
quelle
1
Ich mag Ihre Art, das Schlüsselkonzept zu veranschaulichen. Es könnte besser sein, wenn Sie die Comparer (T) -Klasse in diesen Wettbewerb einbeziehen. Auch ist es nicht in der Frage enthalten. :)
Kevman
4

Wie andere gesagt haben, tun sie nicht dasselbe.

Auf jeden Fall neige ich heutzutage dazu, IComparer nicht zu verwenden. Warum sollte ich? Seine Verantwortung (eine externe Entität, die zum Vergleichen von zwei Objekten verwendet wird) kann mit einem Lambda-Ausdruck viel sauberer gehandhabt werden, ähnlich wie die meisten Methoden von LINQ funktionieren. Schreiben Sie ein schnelles Lambda, das die zu vergleichenden Objekte als Argumente verwendet und einen Bool zurückgibt. Und wenn das Objekt seine eigene intrinsische Vergleichsoperation definiert, kann es stattdessen IComparable implementieren.

jalf
quelle
1
-1: Die Rückgabe eines Bools entspricht nicht IComparer. IComparer gibt einen Wert zurück, der kleiner als Null / Null / größer als Null sein kann und normalerweise zum Sortieren verwendet wird.
Joe
Und wenn Sie dies benötigen, geben Sie stattdessen ein int (oder noch besser eine Aufzählung) zurück. Ist das wirklich eine große Sache?
Jalf
2
Sie können sogar einen Bool zurückgeben, da weniger als die einzige Operation ist, die Sie zum Sortieren einer Sequenz benötigen.
Jalf
Eine IComparer-Implementierung muss nur einmal definiert werden. Wenn Sie die Sortierlogik an mehreren Stellen verwenden müssen, muss der Lambda-Ausdruck mehrmals geschrieben werden.
6.
oɔɯǝɹ - Dann können Sie einen Verweis auf den Delegaten speichern, der als Lambda-Ausdruck geschrieben wurde, und ihn ebenfalls wiederverwenden.
Jpierson
3

IComparable sagt, dass ein Objekt mit einem anderen verglichen werden kann. IComparer ist ein Objekt, das zwei beliebige Elemente vergleichen kann.

Neil Barnwell
quelle
2

IComparer ist eine Schnittstelle, die zum Sortieren des Arrays verwendet wird. Diese Schnittstelle zwingt die Klasse, die Compare-Methode (T x, T y) zu implementieren, mit der die beiden Objekte verglichen werden. Die Instanz der Klasse, die diese Schnittstelle implementiert hat, wird bei der Sortierung des Arrays verwendet.

IComparable ist eine Schnittstelle, die in dem Typ implementiert ist, der die beiden Objekte desselben Typs vergleichen muss. Diese vergleichbare Schnittstelle zwingt die Klasse, die folgende Methode CompareTo (T obj) zu implementieren.

IEqualityComparer ist eine Schnittstelle, die verwendet wird, um das Objekt zu finden, unabhängig davon, ob es gleich ist oder nicht. Jetzt sehen wir dies in einem Beispiel, in dem wir den Unterschied eines Objekts in einer Sammlung finden müssen. Diese Schnittstelle implementiert eine Methode Equals (T obj1, T obj2).

Jetzt nehmen wir ein Beispiel, wir haben eine Employee-Klasse, basierend auf dieser Klasse müssen wir eine Sammlung erstellen. Jetzt haben wir die folgenden Anforderungen.

Sortieren Sie das Array mit der Array-Klasse 2. Benötigen Sie eine Sammlung mit Linq: Entfernen Sie das Duplikat, Ordnen Sie nach höher zu niedriger, Entfernen Sie eine Mitarbeiter-ID

abstract public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { set; get; }
}

public enum SortType
{
    ByID,
    BySalary
}

öffentliche Klasse EmployeeIdSorter: IComparer {public int Compare (Mitarbeiter x, Mitarbeiter y) {if (x.Id <y.Id) return 1; sonst wenn (x.Id> y.Id) -1 zurückgibt; sonst 0 zurückgeben; }}

    public class EmployeeSalarySorter : IComparer<Employee>
    {
        public int Compare(Employee x, Employee y)
        {
            if (x.Salary < y.Salary)
                return 1;
            else if (x.Salary > y.Salary)
                return -1;
            else
                return 0;
        }
    }

Weitere Informationen finden Sie unter http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

Rajesh G.
quelle