Ist die IComparable-Schnittstelle veraltet / "schädlich"?

11

IComparable funktioniert nur in eine Richtung

Angenommen, Sie haben eine EmployeeKlasse. In einer Ansicht möchten Sie alle Employeesnach Namen sortiert anzeigen - in einer anderen nach Adresse. Wie wirst du das erreichen? Nicht mit IComparable, zumindest nicht in irgendeiner Weise.

IComparable hat die Logik am falschen Ort

Die Schnittstelle wird durch Aufruf verwendet .Sort(). In einer Ansicht, die Customernach Namen sortiert angezeigt wird, gibt es überhaupt keinen Code, der impliziert, wie er sortiert werden soll.
Andererseits geht die CustomerKlasse davon aus, wie sie verwendet werden soll - in diesem Fall wird sie in einer nach Namen sortierten Liste verwendet.

IComparable wird implizit verwendet

Im Vergleich zu den Alternativen ist es sehr schwierig zu erkennen, wo die Vergleichslogik verwendet wird - oder wenn überhaupt. Unter der Annahme Ihrer Standard-IDE und ausgehend von der CustomerKlasse muss ich

  1. Suchen Sie nach allen Verweisen auf Customer
  2. Suchen Sie die Referenzen, die in einer Liste verwendet werden
  3. Überprüfen Sie, ob diese Listen sie jemals .Sort()aufgerufen haben

Was wahrscheinlich schlimmer ist, wenn Sie eine IComparableImplementierung entfernen , die noch verwendet wird, erhalten Sie keine Fehler oder Warnungen. Das einzige, was Sie bekommen, ist falsches Verhalten an allen Orten, die zu dunkel waren, als dass Sie daran denken könnten.

Diese Probleme zusammen mit sich ändernden Anforderungen

Der Grund, warum ich darüber nachgedacht habe, ist, dass es für mich schief gelaufen ist. Ich benutze IComparablemeine Anwendung seit 2 Jahren gerne . Jetzt haben sich die Anforderungen geändert und das Ding muss auf zwei verschiedene Arten sortiert werden. Es ist aufgefallen, dass es keinen Spaß macht, die im vorherigen Abschnitt beschriebenen Schritte durchzugehen.

Die Frage

Diese Probleme lassen mich IComparableals minderwertig ICompareroder .OrderBy()bis zu dem Punkt denken , dass ich keinen gültigen Anwendungsfall sehe, der durch die Alternativen nicht besser bedient werden könnte.
Ist es immer besser, ICompareroder LINQ zu verwenden, oder gibt es Vorteile / Anwendungsfälle, die ich hier nicht sehe?

R. Schmitz
quelle
2
Ihre neue Anforderung "Zwei verschiedene Arten sortieren" ist ein roter Hering. Um dies zu lösen, müssen Sie lediglich einen anderen Komparator an Ihre Sortierfunktion übergeben.
Robert Harvey
@RobertHarvey Dann würden Sie nicht IComparablemehr verwenden, was meinen Standpunkt verstärkt.
R. Schmitz
Vergessen Sie nicht, dass bei Verwendung der SortedXXXSammlungen entweder die gespeicherten Elemente vorhanden sein müssen IComparableoder IComparerbereitgestellt werden müssen. Beachten Sie auch, dass es trivial ist, die natürliche Sortierreihenfolge mit einem Vergleicher umzukehren und mit allen IComparableObjekten arbeiten zu lassen.
Berin Loritsch
2
Es spielt keine Rolle, dass es zwei verschiedene Schnittstellen gibt. IComparablewird als Standardvergleichsmechanismus angesehen . IComparerwird verwendet, wenn Sie den Standardvergleichsmechanismus überschreiben möchten.
Robert Harvey
Beispiel ReverseComparer<T>: gist.github.com/jackfarrington/078e7af7bc82482aa634
Berin Loritsch

Antworten:

14

IComparablehat die Einschränkungen, die Sie erwähnt haben, das ist richtig. Es ist eine Schnittstelle, die bereits in .NET Framework 1.0 verfügbar war, wo diese funktionalen Alternativen und Linq nicht verfügbar waren. Ja, man könnte es als veraltetes Framework-Element betrachten, das hauptsächlich aus Gründen der Abwärtskompatibilität beibehalten wird.

Für viele einfache Datenstrukturen ist jedoch eine Art der Sortierung wahrscheinlich ausreichend oder natürlich. In diesen Fällen ist ein kanonischer Ort zum Implementieren der Ordnungsbeziehung immer noch eine gute Möglichkeit, den Code DRY zu halten, anstatt immer die gleiche Logik bei jedem Aufruf an den OrderBygesamten Ort zu wiederholen .

Sie haben "IComparable seit 2 Jahren gerne in Ihrer Anwendung verwendet", wie Sie geschrieben haben, und es scheint mir, dass es Ihnen lange Zeit gute Dienste geleistet hat. Wenn Sie jetzt alle Anrufe validieren, ändern und testen müssen Sort, kann dies auch ein Zeichen dafür sein, dass Sie an vielen Stellen dieselbe Art von Sortierlogik ausgeführt haben, was nicht die Schuld von ist IComparable. Dies könnte also eine Gelegenheit sein, mehr von dieser Logik an einem Ort zu zentralisieren und Ihren Code trockener zu machen.

Doc Brown
quelle
Guter Punkt zu den einfachen Datenstrukturen. Der letzte Absatz macht für mich jedoch keinen 100% igen Sinn. Wenn ich nicht verwendet hätte IComparable, wäre der gesamte bereits vorhandene Sortiercode in den jeweiligen Ansichten unberührt geblieben, während ich nur neuen Sortiercode für die neue Ansicht hinzugefügt hätte.
R. Schmitz
@ R.Schmitz Hätte die bereits vorhandene Sortierung ohne die von IComparableIhnen geschriebene Implementierung korrekt funktioniert ?
Robert Harvey
3
@ R.Schmitz: Sicher, aber jetzt sind Sie verpflichtet, immer einen Komparator bereitzustellen (es sei denn, Sie verwenden natürlich OrderBy). Mit erhalten IComparableSie eine kostenlose Standardimplementierung, und manchmal müssen Sie diese Implementierung nicht einmal schreiben.
Robert Harvey
2
@ R.Schmitz: Dein letzter Kommentar dort fasst den Punkt gut zusammen. Ich würde allerdings etwas weiter gehen. Angenommen, Sie haben einen numerischen Typ wie BigInteger. Wenn es keine Vergleichsoperatoren / -schnittstellen implementieren würde, wie würden Sie selbst einen IComparer implementieren ? Sie benötigen Zugriff auf die internen Datenstrukturen, um dies effizient oder überhaupt zu tun. Angenommen, Sie haben einen Typ wie Kunde. Die öffentlichen Objekte, nach denen Sie sortieren möchten, verfügen über Vergleicher. Für mich ist das der Unterschied: Implementieren, IComparable<T>wenn es nicht zumutbar wäre, vom Aufrufer die Implementierung eines Vergleichers zu erwarten.
Eric Lippert
1
If I hadn't used IComparable, all the pre-existing sorting code would have been left untouched in their respective views, while I'd only add new sorting code for the new view.Nur weil IComparablees zu dieser Zeit eine bessere Lösung war , heißt das nicht, dass es heute die beste Lösung ist . Ihr erster Kommentar hier impliziert, dass "es ist unvergleichbar oder nichts", was nicht wahr ist, das Problem hätte auf viele verschiedene Arten gelöst werden können. Anwendungen können an Größe / Umfang zunehmen, und Dinge, die früher geeignet aussahen, können möglicherweise nicht mit den steigenden Anforderungen der Anwendung Schritt halten.
Flater
1

Ich stimme Ihren Ansichten zu IComparable

Schauen Sie sich einfach die Anmerkungen zu an Array.Sort()

  • Jedes Element des Arrays muss die IComparableSchnittstelle implementieren , um Vergleiche mit jedem anderen Element im Array durchführen zu können. (oder Ausnahme wird ausgelöst)
  • Wenn die Sortierung nicht erfolgreich abgeschlossen wurde, sind die Ergebnisse undefiniert.

Wir werden jetzt aber wahrscheinlich nie die Motivation haben! Betrachten Sie object.Equals()eine Methode für jedes Objekt, mit der Sie Objekte miteinander vergleichen können, um festzustellen, ob sie "gleich" sind.

Sie haben das bereits dort, wurden jedoch mit dem Hinzufügen beauftragt, das Array.Sort()Sie möglicherweise hinzufügen möchtenobject.Compare(object)

Ewan
quelle