Was ist der Unterschied zwischen IComparable- und IEquatable-Schnittstellen?

97

Beide Schnittstellen scheinen Objekte auf Gleichheit zu vergleichen. Was sind also die Hauptunterschiede zwischen ihnen?

SoftwareGeek
quelle

Antworten:

188

IEquatable testet, ob zwei Objekte gleich sind.

IComparable legt den zu vergleichenden Objekten eine Gesamtreihenfolge auf.

Zum Beispiel IEquatablewürde ich Ihnen sagen, dass 5 nicht gleich 7 ist. IComparableWürde Ihnen sagen, dass 5 vor 7 kommt.

Greg D.
quelle
20

IEquatable<T> für die Gleichheit.

IComparable<T> zur Bestellung.

Islam Yahiatene
quelle
10

Zusätzlich zu Greg Ds Antwort:

Sie könnten implementieren , IComparableohne die Umsetzung IEquatablefür eine Klasse , wo eine partielle Ordnung Sinn macht, und wo man sehr auf jeden Fall den Verbraucher zu schließen wollen , dass nur weil CompareTo()Null zurückgibt, dies nicht bedeutet , dass die Objekte gleich sind (für etwas anderes als Sortierzwecke).

Damien_The_Unbeliever
quelle
10
Das klingt viel mehr nach einem Spezialfall-Vergleicher als nach einem Objekt, das IComparableordnungsgemäß implementiert wird. Können Sie mit einem aussagekräftigen Beispiel kommen , wenn CompareTo(…) == 0sie nicht der Gleichheit bedeuten? Ich kann es bestimmt nicht. Tatsächlich erfordert der Schnittstellenvertrag (gemäß MSDN) , dass CompareTo(…) == 0Gleichheit impliziert wird. Um es ganz klar auszudrücken: Verwenden Sie in einem Fall wie Ihrem ein spezielles ComparatorObjekt und implementieren Sie es nichtIComparable .
Konrad Rudolph
2
@Konrad - Ich habe einige Vorbehalte angegeben - dass der Typ IEquatable nicht implementiert (daher möchte der Urheber offensichtlich keinen Gleichheitstest einschließen) und dass CompareTo-Ergebnisse zum Sortieren und nicht zum Bewerten der Gleichheit verwendet werden. Sie geraten auch in Fragen, welche Gleichheit relevant ist (Referenz, Wert, Ignorieren "willkürlicher" Attribute - ein blaues Buch mit einer Länge von 500 Seiten kann für die Zwecke von IComparable einem roten Buch mit einer Länge von 500 Seiten "gleich" sein).
Damien_The_Unbeliever
4
Ihr letzter Satz ist falsch, und dies ist der besondere Fehler, auf den ich hinweisen wollte: IComparableist hier völlig unangemessen. Was Sie haben, ist eine ganz bestimmte Bestellung, die nur in einer speziellen Situation gilt. In solchen Situationen ist die Implementierung eines Generals IComparablefalsch. Dafür sind wir IComparerda. Zum Beispiel können Personen nicht sinnvoll bestellt werden. Sie können jedoch nach ihrem Gehalt, ihrer Schuhgröße, der Anzahl ihrer Sommersprossen oder ihrem Gewicht bestellt werden. Daher würden wir IComparerfür all diese Fälle unterschiedliche s implementieren .
Konrad Rudolph
2
@Konrad Rudolph: Was ist mit so etwas wie einer "ScheduledEvent" -Klasse, die zu einem bestimmten Zeitpunkt "etwas" tun soll? Die Semantik des Typs würde eine sehr starke natürliche semantische Ordnung implizieren, die darauf basiert, wann die Aktion stattfinden sollte, aber es könnte leicht sein, dass verschiedene Ereignisse gleichzeitig auftreten. Man könnte die Verwendung eines manuell spezifizierten IComparers verlangen, aber ich würde sagen, dass es bequemer wäre, einen in die Klasse eingebauten Komparator zu haben.
Supercat
4
@supercat Convenience ist wichtig, aber es ist nicht alles. Korrektheit (wie in, logische Konsistenz) ist wichtiger und das statische Typsystem ist ein wichtiges Werkzeug zur Überprüfung dieser logischen Konsistenz. Indem Sie gegen den dokumentierten Vertrag der von Ihnen implementierten Schnittstellen verstoßen, untergraben Sie das Typsystem. Dies ist keine gute Idee, und ich würde es niemals empfehlen. Verwenden Sie für solche Situationen einen externen Vergleicher.
Konrad Rudolph
7

Wie auf der MSDN-Seite für IEquatable angegeben :

Die IComparable-Schnittstelle definiert die CompareToMethode, die die Sortierreihenfolge der Instanzen des Implementierungstyps bestimmt. Die IEquatable-Schnittstelle definiert die EqualsMethode, die die Gleichheit der Instanzen des Implementierungstyps bestimmt.

Equals vs. CompareTo

Will Eddins
quelle
2

IComparable <T> definiert eine typspezifische Vergleichsmethode, mit der Objekte sortiert oder sortiert werden können.

IEquatable <T> definiert eine verallgemeinerte Methode, die zur Bestimmung der Gleichheit implementiert werden kann.


Angenommen, Sie haben eine Personenklasse

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person p1 = new Person() { Name = "Person 1", Age = 34 };
Person p2 = new Person() { Name = "Person 2", Age = 31 };
Person p3 = new Person() { Name = "Person 3", Age = 33 };
Person p4 = new Person() { Name = "Person 4", Age = 26 };

List<Person> people = new List<Person> { p1, p2, p3, p4 };

Um diese Objekte zu sortieren, können Sie verwenden people.Sort();.

Dies wird jedoch eine Ausnahme auslösen.

Geben Sie hier die Bildbeschreibung ein

Framework kann diese Objekte nicht sortieren. Sie müssen angeben, wie die Implementierungsschnittstelle sortiert IComparablewerden soll.

public class Person : IComparable
{
    public string Name { get; set; }
    public int Age { get; set; }

    public int CompareTo(object obj)
    {
        Person otherPerson = obj as Person;
        if (otherPerson == null)
        {
            throw new ArgumentNullException();
        }
        else
        {
            return Age.CompareTo(otherPerson.Age);
        }
    }
}

Dadurch wird das Array mit der Sort()Methode ordnungsgemäß sortiert .


Um zwei Objekte zu vergleichen, können Sie die Equals()Methode verwenden.

var newPerson = new Person() { Name = "Person 1", Age = 34 };
var newPersonIsPerson1 = newPerson.Equals(p1);

Dies wird zurückgegeben,false da die EqualsMethode nicht weiß, wie zwei Objekte verglichen werden sollen. Daher müssen Sie die IEquatableSchnittstelle implementieren und dem Framework mitteilen, wie der Vergleich durchgeführt werden soll. Wenn Sie das vorherige Beispiel erweitern, sieht es so aus.

public class Person : IComparable, IEquatable<Person>
{
    //Some code hidden

    public bool Equals(Person other)
    {
        if (Age == other.Age && Name == other.Name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}
Nipuna
quelle
1
Danke für diese tolle Erklärung. Frage: Warum wird IEquatableein Generikum verwendet <Person>und IComparablenicht?
veuncent