5 Stimmen

Hash-Codes für unveränderliche Typen

Gibt es irgendwelche Überlegungen für unveränderliche Typen in Bezug auf Hash-Codes?

Sollte ich sie einmal im Konstruktor erzeugen?

Wie würden Sie deutlich machen, dass der Hash-Code festgelegt ist? Sollte ich das? Wenn ja, ist es besser, eine Eigenschaft namens HashCode zu verwenden, anstatt die Methode GetHashCode? Hätte das irgendeinen Nachteil? (Wenn man bedenkt, dass beides funktionieren würde, aber die Eigenschaft zu empfehlen wäre).

18voto

Eric Lippert Punkte 628543

Gibt es irgendwelche Überlegungen für unveränderliche Typen in Bezug auf Hash-Codes?

Unveränderliche Typen sind am einfachsten korrekt zu hashen; die meisten Hash-Code-Fehler treten beim Hashing veränderlicher Daten auf. Das Wichtigste ist, dass Hashing und Gleichheit übereinstimmen; wenn zwei Instanzen als gleich verglichen werden, sollten sie den gleichen Hash-Code haben. (Der umgekehrte Fall ist nicht notwendigerweise wahr; zwei Instanzen, die den gleichen Hash haben, müssen nicht gleich sein.)

Sollte ich sie einmal im Konstruktor erzeugen?

Das ist eine Technik zur Leistungsoptimierung; auf diese Weise tauschen Sie den erhöhten Platzbedarf (für die Speicherung des berechneten Wertes) gegen eine mögliche Zeitersparnis. I niemals Leistungsoptimierungen vorzunehmen, es sei denn, sie beruhen auf realistischen, kundenorientierten Leistungstests, bei denen die Leistung beider Optionen sorgfältig anhand dokumentierter Ziele gemessen wird. Sie sollten dies tun, wenn Ihre sorgfältig konzipierten Experimente zeigen, dass Sie (1) Ihr Ziel verfehlen, wenn Sie dies nicht tun, und (2) wenn Sie Ihr Ziel erreichen, wenn Sie dies tun.

Wie würden Sie deutlich machen, dass der Hash-Code festgelegt ist?

Ich verstehe die Frage nicht. Ein sich ändernder Hash-Code ist die Ausnahme, nicht die Regel. Hash-Codes sollen immer unveränderlich sein. Wenn sich der Hash-Code eines Objekts ändert, kann das Objekt in einer Hash-Tabelle "verloren" gehen, daher sollte jeder davon ausgehen, dass Hash-Codes stabil bleiben.

Ist es besser, eine Eigenschaft namens HashCode zu verwenden, anstatt die Methode GetHashCode?

Welcher Verbraucher Ihres Objekts wird sagen: "Nun, ich könnte GetHashCode() aufrufen, eine Methode, die garantiert bei allen Objekten vorhanden ist, aber stattdessen rufe ich diesen HashCode-Getter auf, der genau das Gleiche tut"? Haben Sie einen solchen Verbraucher im Sinn?

Wenn Sie keine Verbraucher für die Funktionalität haben, dann stellen Sie die Funktionalität nicht zur Verfügung.

9voto

Jon Skeet Punkte 1325502

Normalerweise würde ich sie nicht im Konstruktor generieren, aber ich würde auch mehr über die erwartete Verwendung wissen wollen, bevor ich entscheide, ob ich sie zwischenspeichern soll oder nicht.

Erwarten Sie eine kleine Anzahl von Instanzen, die sehr oft gehasht werden und für die Berechnung des Hashes viel Zeit benötigen? Wenn ja, könnte Caching sinnvoll sein. Wenn Sie eine große Anzahl von potenziell "wegwerfbaren" Instanzen erwarten, würde ich mich nicht um Caching bemühen.

Interessanterweise haben .NET und Java in dieser Hinsicht unterschiedliche Entscheidungen für String getroffen - Java speichert den Hash, .NET nicht. Angesichts der Tatsache, dass viele String-Instanzen niemals gehasht, und solche, die son Hashes werden oft nur einmal gehasht (z.B. beim Einfügen in die Hash-Tabelle). Ich denke, ich bevorzuge hier die Entscheidung von .NET.

Im Grunde tauschen Sie Speicher und Komplexität gegen Geschwindigkeit. Wie Michael sagt: Testen Sie, bevor Sie Ihren Code komplexer machen. Natürlich kann man in manchen Fällen (z. B. bei einer Klassenbibliothek) die tatsächliche Nutzung nicht genau vorhersagen, aber in vielen Situationen hat man eine ziemlich gute Vorstellung.

Eine eigene Immobilie brauchen Sie allerdings nicht. Hash-Codes sollten immer gleich bleiben, es sei denn, jemand ändert den Zustand des Objekts - und wenn Ihr Typ unveränderlich ist, sind Sie bereits verbieten, dass, daher sollte ein Benutzer keine Änderungen zu erwarten. Überschreiben Sie einfach GetHashCode() .

4voto

Bill the Lizard Punkte 384619

Ich würde den Hash-Code einmal generieren, wenn getHashCode das erste Mal aufgerufen wird, und dann für spätere Aufrufe zwischengespeichert wird. Dadurch wird vermieden, dass er im Konstruktor aufgerufen wird, wenn er möglicherweise nicht benötigt wird.

Wenn Sie nicht erwarten, dass Sie anrufen getHashCode sehr viele Male für jedes Wertobjekt, müssen Sie den Wert möglicherweise gar nicht zwischenspeichern.

3voto

Michael Petrotta Punkte 58361

Nun, Sie müssen eine überschriebene Methode GetHashCode() haben, da dies die Art und Weise ist, wie die Verbraucher Ihren Hashcode abrufen werden. Die meisten Hashcodes sind recht einfache arithmetische Operationen, die schnell ausgeführt werden können. Haben Sie Grund zu der Annahme, dass das Zwischenspeichern der Ergebnisse (das Speicher kostet) eine spürbare Leistungssteigerung bringt?

Fangen Sie einfach an - generieren Sie den Hashcode im Handumdrehen. Wenn Sie glauben, dass Sie durch das Zwischenspeichern Leistungsverbesserungen erzielen, testen Sie es zuerst.

Vorschriftsmäßig muss ich Sie an dieser Stelle auf das Zitat "Vorzeitige Optimierung ist die Wurzel allen Übels" verweisen.

2voto

Rinat Abdullin Punkte 22138

Aus meiner persönlichen Erfahrung weiß ich, dass Entwickler sind sehr gut darin, Leistungsprobleme falsch einzuschätzen. .

Es wird daher empfohlen alles so einfach wie möglich halten bei der Berechnung des Hash-Codes während der Ausführung der Funktion GetHashCode().

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X