Distinct und Equals
-
Hallo,
ich hab ein (eigentlich) simples Problem. Ich habe eine Liste mit 3-Dimensionalen Punkten, also etwa so:
class Point3D { public double x, y, z; // ... } // ... List<Point3D> points; // .... points = points.Distinct(); // Soll alle verschiedenen Werte zurückgeben
Aus dieser Liste will ich jetzt alle Duplikate entfernen. Ein Duplikat ist dann vorhanden wenn alle Werte x, y und z von zwei
Point3D
Objekten gleich sind. Also will ich Distinct benutzen.Dafür muss ich ja eigentlich nur Equals überschreiben. Allerdings bekomme ich dann eine Warnung, dass ich
Equals
, aber nichtGetHashCode
überschreibe. Also will ich auchGetHashCode
überschreiben, wie etwa hier gezeigt.Allerdings steht hier bei MSDN (obwohl in dem ersten Link anders gezeigt) folgendes: "It is not a good idea to override operator == in non-immutable types.". Gleichzeitig wird aber empfohlen den
operator==
zu überschreiben, wenn manEquals
überschreibt.So, auf jeden Fall steh ich jetzt in einer logischen Sackgasse:
- Ich will
Distinct
basierend auf einem eigenen Vergleichsoperator verwenden, also überschreibe ichEquals
. - Die Empfehlung ist, wenn Equals überschrieben wird, auch
operator==
zu überschreiben. - Allerdings wird gleichzeitig empfohlen das nur bei immutable Objekten zu machen, was mein Punkt aber nicht ist (und auch nicht sein soll).
Mit
GetHashCode
ist das gleiche Problem, bei SO wird etwa gesagt man solle den Hash nur aus immutable Membern berechnen, da sonst Einträge in einem Dictionary invalidiert werden könnten.TL;DR: Wie macht mans wirklich richtig? Eigentlich sollte das doch nicht so kompliziert sein, oder?
- Ich will
-
happystudent schrieb:
Gleichzeitig wird aber empfohlen den
operator==
zu überschreiben, wenn manEquals
überschreibt.Wo steht das denn?
-
MFK schrieb:
Wo steht das denn?
In dem SO link (in der akzeptieren Antwort mit über 600 Upvotes. Da gibt es zwar auch eine Diskussion über das Thema, aber eine entgültige Empfehlung, wie es jtzt tatsächlich richtig ist, kann ich da nicht wirklich rauslesen.
Mich verwirrt vor allem dass irgendwie nicht klar ist was man machen soll wenn man ein mutable Objekt hat und dafür
Equals
(und damit automatisch auchGetHashCode
) überschreiben will.
-
happystudent schrieb:
In dem SO link (in der akzeptieren Antwort mit über 600 Upvotes.
Da steht, du kannst es aus Bequemlichkeitsgründen erwägen. Und einer der Kommentare verweist darauf, dass Microsoft davon abrät.
happystudent schrieb:
Mich verwirrt vor allem dass irgendwie nicht klar ist was man machen soll wenn man ein mutable Objekt hat und dafür Equals (und damit automatisch auch GetHashCode) überschreiben will.
In deinem Fall würde ich einfach die Distinct-Überladung verwenden, die einen zusätzlichen IEqualityComparer-Parameter hat.
-
MFK schrieb:
Da steht, du kannst es aus Bequemlichkeitsgründen erwägen. Und einer der Kommentare verweist darauf, dass Microsoft davon abrät.
Ok, dann lass ich den schonmal weg.
happystudent schrieb:
In deinem Fall würde ich einfach die Distinct-Überladung verwenden, die einen zusätzlichen IEqualityComparer-Parameter hat.
Da hab ich aber das gleiche Problem, weil da muss ich ja auch GetHashCode implementieren (bei IEqualityComparer sogar gezwungenermaßen da Interface).
Und da ist ja wieder da Problem dass der Hashcode aus mutable Datamembern generiert würde. Muss man mit diesem Problem also einfach leben?
Ich finde das ja schon ziemlich nervig dass Equals und GetHashCode so eng miteinander verbunden sind. Eigentlich sind das ja zwei verschiedene Sachen, also sollte man auch zwei verschiedene Interfaces dafür anbieten...
-
happystudent schrieb:
Da hab ich aber das gleiche Problem, weil da muss ich ja auch GetHashCode implementieren (bei IEqualityComparer sogar gezwungenermaßen da Interface).
Nein, da die Hashes nur für diesen einen Distinct-Aufruf gelten müssen. Damit hast du hier kein Problem mit veränderlichen Membern.
-
MFK schrieb:
Nein, da die Hashes nur für diesen einen Distinct-Aufruf gelten müssen. Damit hast du hier kein Problem mit veränderlichen Membern.
Ahh, hat Klick gemacht, vielen Dank