Frage

Ich habe über 10 verschiedene Fragen zu lesen, wann und wie GetHashCode außer Kraft zu setzen, aber es gibt noch etwas, das ich nicht ganz bekommen. Die meisten Implementierungen von GetHashCode sind auf den Hash-Codes der Felder des Objekts basiert, aber es wird zitiert worden, dass der Wert von GetHashCode nie über die gesamte Lebensdauer des Objekts ändern sollte. Wie funktioniert das, wenn die Felder, die es basiert auf veränderlich sind? Auch wenn ich Wörterbuch Lookups etc will, basierend auf Referenz Gleichheit nicht mein außer Kraft gesetzt Equals werden?

Ich bin in erster Linie überwiegendes Equals für die einfache Einheit meiner Serialisierungscode Prüfung, die ich nehme an der Serialisierung und Deserialisierung (auf XML in meinem Fall) tötet die Referenz Gleichheit, damit ich sicher, zumindest machen will sie durch Wertgleichheit korrekt sind. Ist die schlechte Praxis Equals in diesem Fall außer Kraft zu setzen? Im Grunde genommen in den meisten der Ausführung von Code Ich möchte Referenz Gleichheit und ich verwende == immer und ich bin überschreiben, dass es nicht. Sollte ich nur eine neue Methode ValueEquals oder etwas anstelle des überwiegenden Equals? Früher habe ich davon ausgehen, dass das Framework verwendet immer == und nicht Equals Dinge zu vergleichen und so dachte ich, es war sicher Equals außer Kraft zu setzen, da schien es mir, wie ihr Zweck für war, wenn Sie wollen eine zweite Definition der Gleichheit haben, die von der anders ist == Betreiber. einige andere Fragen aus der Lektüre obwohl es scheint, dass das nicht der Fall.

EDIT:

Es scheint, dass meine Absichten waren unklar, was ich meine ist, dass 99% der Zeit, die ich nur alte Referenz Gleichheit, Standardverhalten will, keine Überraschungen. Bei sehr seltenen Fällen möchte ich Wert Gleichheit haben, und ich möchte ausdrücklich Wert Gleichheit verlangen von .Equals statt == verwenden.

Wenn ich dies tun, der Compiler empfiehlt ich GetHashCode auch außer Kraft setzen, und das ist, wie diese Frage kam. Es schien, als gäbe es Ziele für GetHashCode widersprechen, wenn sie veränderbare Objekte angewendet, jene Wesen:

  1. Wenn a.Equals(b) dann sollte a.GetHashCode() == b.GetHashCode().
  2. Der Wert von a.GetHashCode() sollte nie über die gesamte Lebensdauer von a ändern.

Diese scheinen natürlich im Widerspruch, wenn ein veränderbares Objekt, denn wenn der Zustand des Objekts ändert, wir den Wert von .Equals() zu ändern erwarten, was bedeutet, dass GetHashCode sollte die Änderung in .Equals() anzupassen ändern, aber GetHashCode sollte nicht geändert werden.

Warum scheint es dieser Widerspruch zu sein? Werden diese Empfehlungen nicht veränderbare Objekte anwenden zu verstehen? Wahrscheinlich angenommen, aber vielleicht erwähnenswert Ich beziehe mich auf Klassen nicht structs.

Auflösung:

Ich bin Kennzeichnung JaredPar als angenommen, aber vor allem für die Kommentare Interaktion. Um es zusammenzufassen, was ich gelernt habe, von diesem ist, dass der einzige Weg, um alle Ziele zu erreichen und mögliche schrulligen Verhalten in Grenzfällen zu vermeiden, ist nur außer Kraft zu setzen Equals und GetHashCode basierend auf unveränderlichen Felder oder IEquatable zu implementieren. Diese Art von scheint die Nützlichkeit des überwiegenden Equals für Referenztypen zu vermindern, als von dem, was ich am meisten Referenztypen in der Regel keine unveränderlichen Felder haben gesehen haben, wenn sie in einer relationalen Datenbank gespeichert sind, um sie mit ihren Primärschlüssel zu identifizieren.

War es hilfreich?

Lösung

Wie funktioniert das, wenn die Felder, die es basiert auf veränderlich sind?

Es ist nicht in dem Sinne, dass der Hash-Code wie die Objektänderungen ändern wird. Das ist ein Problem für alle aufgeführten Gründen in den Artikeln, die Sie lesen. Leider ist dies die Art von Problem, das normalerweise nur in Fällen Ecke angezeigt. So neigen Entwickler mit dem schlechten Verhalten wegzukommen.

Auch wenn ich etc Wörterbuch Lookups tun will basieren auf Referenz Gleichheit nicht mein überschriebene Equals?

Solange Sie eine Schnittstelle wie IEquatable<T> implementieren dies kein Problem sein sollte. Die meisten Wörterbuch-Implementierungen wird eine Gleichheitsvergleichs in einer Art und Weise wählen, die IEquatable<T> über Object.ReferenceEquals verwenden. Auch ohne IEquatable<T>, wird standardmäßig die meisten zu nennen Object.Equals (), die dann in die Umsetzung gehen.

Im Grunde genommen in den meisten der Ausführung von Code Ich möchte Referenz Gleichheit und ich verwende immer == und ich bin überschreiben, dass es nicht.

Wenn Sie erwarten, dass Ihre Objekte mit Wertgleichheit verhalten Sie außer Kraft setzen sollte == und! = Wertgleichheit für alle Vergleiche zu erzwingen. Benutzer können immer noch Object.ReferenceEquals verwenden, wenn sie tatsächlich Referenz Gleichheit wollen.

Früher habe ich davon ausgehen, dass das Framework verwendet immer == und nicht Equals Dinge vergleichen

Was die BCL Anwendungen ein wenig im Laufe der Zeit verändert hat. Jetzt sind die meisten Fälle, die Gleichheit verwenden eine IEqualityComparer<T> Beispiel nehmen und es für die Gleichstellung verwenden. In den Fällen, in denen eine nicht angegeben werden sie EqualityComparer<T>.Default zu finden, verwenden. Im schlimmsten Fall, dies zu fordern Object.Equals ausfällt

Andere Tipps

Wenn Sie ein veränderbares Objekt haben, gibt es nicht viel Sinn, die GetHashCode-Methode in überschreiben, da Sie nicht wirklich nutzen können. Es ist zum Beispiel durch die Dictionary und HashSet Sammlungen verwendet, um jedes Element in einem Eimer zu platzieren. Wenn Sie das Objekt ändern, während sie als Schlüssel in der Sammlung verwendet wird, nicht der Hash-Code mehr entspricht den Eimer, der das Objekt in ist, so dass die Sammlung nicht richtig funktioniert und Sie können nie wieder das Objekt finden.

Wenn Sie die Suche wollen die GetHashCode oder Equals nicht verwenden Methode der Klasse, können Sie immer Ihre eigene IEqualityComparer Implementierung zur Verfügung stellen, anstatt zu verwenden, wenn Sie die Dictionary erstellen.

Die Equals Methode wird für Wertgleichheit soll, so ist es nicht falsch, es so zu implementieren.

Wow, das ist eigentlich eine Reihe von Fragen in einem :-). So eins nach dem anderen:

  

es zitiert worden, dass der Wert von GetHashCode sollte nie über die gesamte Lebensdauer des Objekts ändern. Wie funktioniert das, wenn die Felder, die es basiert auf veränderlich sind?

Diese gemeinsame Beratung ist für den Fall gedacht, wo Sie Ihr Objekt als Schlüssel in einem HashTable / Wörterbuch usw. verwenden möchten. HashTables erfordern in der Regel den Hash nicht zu ändern, da sie es verwenden, um zu entscheiden, wie Sie die Schlüssel zu speichern und abzurufen. Wenn die Hash ändert, wird der HashTable wahrscheinlich nicht mehr finden Sie Ihr Objekt.

Um die Dokumentation von Java zu zitieren Karte Schnittstelle:

Hinweis: große Sorgfalt ausgeübt werden muß, wenn veränderbare Objekte als Kartenschlüssel verwendet werden. Das Verhalten einer Karte ist nicht festgelegt, wenn der Wert eines Objekts in einer Weise verändert wird, die Vergleiche wirkt sich gleich, während das Objekt ein Schlüssel in der Karte ist.

In der Regel ist es eine schlechte Idee zu verwenden jeder Art veränderbaren Objekts als Schlüssel in einer Hash-Tabelle: Es ist nicht einmal klar, was passiert, wenn ein Schlüssel Änderungen passieren soll, nachdem es in der Hash-Tabelle hinzugefügt wurde . Sollte die Hash-Tabelle, das gespeicherte Objekt über den alten Schlüssel zurück oder über den neuen Schlüssel oder über beides?

Die eigentliche Rat: Verwenden Sie nur unveränderliche Objekte als Schlüssel, und sicherstellen, dass ihre Hash-Code ändert sich nie entweder (was in der Regel automatisch, wenn das Objekt unveränderlich ist)

.
  

Auch wenn ich etc Wörterbuch Lookups tun will auf Verweisgleichheit nicht mein überschriebene Equals zu basieren?

Nun, eine Wörterbuch Umsetzung finden, wie das funktioniert. Aber der Standard-Bibliothek Wörterbücher verwenden, um den Hash-Code & Equals, und es gibt keine Möglichkeit, das zu ändern.

  

Ich bin in erster Linie überwiegende für die einfache Einheit entspricht meine Serialisierungscode Prüfung, die ich die Serialisierung und Deserialisierung (auf XML in meinem Fall) übernehme Gleichheit der Referenz tötet, damit ich sicher, dass zumindest machen will sie durch Wertgleichheit korrekt sind. Ist das schlechte Praxis Equals in diesem Fall außer Kraft zu setzen?

Nein, ich würde feststellen, dass durchaus akzeptabel. Sie sollten jedoch nicht solche Objekte als Schlüssel in einem Wörterbuch / Hash-Tabelle verwenden, wie sie wandelbar sind. Siehe oben.

Das zugrunde liegende Thema hier ist, wie man am besten Objekte eindeutig identifizieren. Sie erwähnen die Serialisierung / Deserialisierung was wichtig ist, weil die referentielle Integrität in diesem Prozess verloren geht.

Die kurze Antwort, ist, dass Objekte sollten eindeutig durch die kleinste Menge von unveränderlichen Feldern identifiziert werden, die verwendet werden können, dies zu tun. Dies sind die Felder, die Sie verwenden sollten, wenn overrideing GetHashCode und Equals.

Für die Prüfung ist es durchaus sinnvoll zu definieren, was Behauptungen, die Sie brauchen, in der Regel ist diese nicht von der Art definiert selbst, sondern als Hilfsmethoden in der Testsuite. Vielleicht ein TestSuite.AssertEquals (MyClass, MyClass)?

Beachten Sie, dass GetHashCode und Equals zusammenarbeiten sollten. GetHashCode sollte den gleichen Wert für zwei Objekte zurück, wenn sie gleich sind. Equals sollte true zurück, wenn und nur wenn zwei Objekte den gleichen Hash-Code haben. (Beachten Sie, dass es möglich ist, dass zwei Objekt nicht gleich sein, sondern kann den gleichen Hash-Code zurück). Es gibt viele Webseiten, die dieses Thema direkt von vorn angehen, einfach weg Google.

Ich weiß nicht, über C #, eine relative noob es zu sein, aber in Java, wenn Sie equals () überschreiben Sie müssen auch hashCode () überschreiben, den Vertrag zwischen ihnen zu halten (und umgekehrt) .. . Und Java hat auch den gleichen Fang 22; im Grunde zwingen Sie unveränderliche Felder verwenden ... Aber das ist ein Thema nur für Klassen, die als Hash-Schlüssel verwendet werden, und Java hat alternative Implementierungen für alle Hash-basierten Sammlungen ... die vielleicht nicht so schnell, aber sie tun effecitely können Sie ein veränderbares Objekt als Schlüssel verwenden ... es ist nur (in der Regel) runzelte die Stirn als ein „schlechtes Design“ auf.

Und ich fühle den Drang, darauf hinzuweisen, dass dieses grundlegende Problem ist zeitlos ... Es ist schon seit Adam ein Junge war.

ich auf Fortran-Code gearbeitet haben, die älter ist als ich bin (ich bin 36), die bricht, wenn ein Benutzername geändert wird (wie wenn ein Mädchen heiratet, oder geschieden ;-) ... So ist Engineering, The angenommen Lösung war: die GetHashCode „Methode“, erinnert sich der zuvor berechneten hashCode, berechnet die hashCode (dh ein virtueller isDirty Marker) und wenn die KeyFields geändert haben es gibt null zurück. Dies bewirkt, dass der Cache-Speicher den „schmutzigen“ Benutzer (durch eine andere GetPreviousHashCode Aufruf) zu löschen und dann der Cache gibt null zurück, so dass der Benutzer aus der Datenbank neu zu lesen. Ein interessanter und wertvoller Hack; selbst wenn ich so sagen darf; -)

Ich werde Abwägen Veränderlichkeit (nur wünschenswert, in Eckfällen) für O (1) Zugang (wünschenswert in allen Fällen). Willkommen bei Engineering; das Land des informierten Kompromisses.

Prost. Keith.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top