Kann object.GetHashCode () unterschiedliche Ergebnisse für die gleichen Objekte (Strings) auf verschiedenen Rechnern erzeugen?

8

Ist es möglich, dass ein und dasselbe Objekt, insbesondere ein string oder ein primitiver oder sehr einfacher Typ (wie ein struct ) unterschiedliche Werte der Methode .GetHashCode() erzeugt, wenn sie auf verschiedenen Maschinen aufgerufen wird?

Zum Beispiel ist es möglich, dass der Ausdruck "Hello World".GetHashCode() einen anderen Wert auf einer anderen Maschine erzeugt. Ich frage hauptsächlich nach C # .NET, aber ich nehme an, dass dies für Java oder sogar andere Sprachen gelten könnte?

Bearbeiten:

Wie aus Antworten und Kommentaren unten hervorgeht, ist% ce_de% möglicherweise überschrieben und es gibt keine Garantie für das Ergebnis, das zwischen verschiedenen Versionen des Frameworks erzeugt wird. Daher ist es wichtig zu verdeutlichen, dass ich einfache Typen im Hinterkopf habe (die nicht vererbt werden können, daher .GetHashCode() überschrieben werden) und ich verwende die gleichen Versionen des Frameworks auf allen Maschinen.

    
Ivaylo Slavov 12.01.2012, 15:56
quelle

2 Antworten

14

Kurze Antwort: Ja.

Aber kurze Antworten machen keinen Spaß, oder?

Wenn Sie GetHashCode() implementieren, müssen Sie folgende Garantie geben:

  

Wenn GetHashCode() für ein anderes Objekt aufgerufen wird, das als gleich betrachtet werden soll, wird in dieser Anwendungsdomäne derselbe Wert zurückgegeben.

Das ist es. Es gibt einige Dinge, die Sie wirklich versuchen sollten (verteilen Sie die Bits so oft wie möglich mit nicht gleichen Objekten, aber nehmen Sie sich nicht so lange Zeit, dass es die Vorteile von Hashing überwiegt) und Ihren Code Wenn du es nicht tust, wird es scheiße, aber es wird nicht wirklich brechen. Es wird brechen, wenn Sie nicht so weit gehen, weil dann z.B.:

%Vor%

Okay. Wenn ich GetHashCode() implementiere, warum kann ich dann weiter gehen und warum nicht?

Erstens, warum könnte ich nicht?

Vielleicht ist es eine etwas andere Version der Assembly und ich habe zwischen Builds verbessert (oder zumindest versucht).

Vielleicht ist 32-Bit und eins ist 64-Bit und ich war verrückt nach Effizienz und wählte einen anderen Algorithmus für jeden, um die verschiedenen Wortgrößen zu verwenden (das ist nicht unbekannt, besonders beim Hashing von Objekten wie Sammlungen) oder Zeichenfolgen).

Vielleicht ist ein Element, das ich bei der Entscheidung darüber, was "gleiche" Objekte ausmacht, zu berücksichtigen, selbst von System zu System auf diese Art und Weise.

Vielleicht führe ich eigentlich einen anderen Seed mit verschiedenen Builds ein, um einen Fall zu erfassen, in dem ein Kollege fälschlicherweise von meinem Hash-Code abhängig ist! (Ich habe gehört, dass MS dies mit ihrer Implementierung für string.GetHashCode() macht, kann sich aber nicht erinnern, ob ich das von einer glaubwürdigen oder leichtgläubigen Quelle gehört habe).

Hauptsächlich wird es jedoch einer der ersten beiden Gründe sein.

Nun, warum könnte ich eine solche Garantie geben?

Wahrscheinlich werde ich es zufällig tun. Wenn ein Element auf der Basis einer einzelnen Ganzzahl-ID allein auf Gleichheit verglichen werden kann, dann werde ich das als meinen Hash-Code verwenden. Alles andere wird mehr Arbeit für einen weniger guten Hash sein. Ich werde das wahrscheinlich nicht ändern, also könnte ich das.

Der andere Grund, warum ich das könnte, ist, dass ich diese Garantie selbst will. Es gibt nichts zu sagen, ich kann es nicht bieten, nur dass ich es nicht muss.

Okay, lass uns zu etwas Praktischem kommen. Es gibt Fälle, in denen Sie eine maschinenunabhängige Garantie benötigen. Es gibt Fälle, in denen Sie das Gegenteil wollen, auf das ich kurz eingehen werde.

Überprüfe zuerst deine Logik. Können Sie mit Kollisionen umgehen? Gut, dann fangen wir an.

Wenn es sich um eine eigene Klasse handelt, implementieren Sie sie, um eine solche Garantie zu geben, dokumentieren Sie sie und Sie sind fertig.

Wenn es nicht Ihre Klasse ist, implementieren Sie IEqualityComparer<T> so, dass Sie es bereitstellen. Zum Beispiel:

%Vor%

Verwenden Sie dann diesen anstelle des integrierten Hash-Codes.

Es gibt einen interessanten Fall, wo wir das Gegenteil wollen. Wenn ich die Menge der Strings kontrollieren kann, die Sie hashen, kann ich eine Menge Strings mit demselben Hash-Code auswählen. Die Leistung Ihrer Hash-basierten Sammlung wird den schlechteren Fall treffen und ziemlich unfassbar sein. Es ist wahrscheinlich, dass ich das schneller machen kann, als Sie damit umgehen können. Es kann sich also um einen Denial-of-Service-Angriff handeln. Es gibt nicht viele Fälle, in denen das passiert, aber eine wichtige ist, wenn Sie mit XML-Dokumenten umgehen, die ich sende, und Sie können nicht einfach einige Elemente ausschließen (viele Formate erlauben die Freiheit von Elementen in ihnen). Dann wird die NameTable in Ihrem Parser verletzt. In diesem Fall erstellen wir jedes Mal einen neuen Hash-Mechanismus:

%Vor%

Dies wird innerhalb einer bestimmten Verwendung konsistent sein, aber nicht konsistent von der Verwendung sein, sodass ein Angreifer keine Eingabe erstellen kann, um es zu DoSsed zu zwingen. Übrigens verwendet NameTable kein IEqualityComparer<T> , weil es sich mit Char-Arrays mit Indizes und Längen befassen will, ohne eine Zeichenkette zu konstruieren, wenn dies nicht notwendig ist, aber es tut etwas ähnliches.

Übrigens wird in Java der Hash-Code für string angegeben und ändert sich nicht, aber dies ist möglicherweise für andere Klassen nicht der Fall.

Edit: Nachdem ich etwas über die Qualität des Ansatzes in ConsistentGuaranteedComparer oben geforscht habe, bin ich nicht mehr glücklich darüber, solche Algorithmen in meinen Antworten zu haben; Während es dazu dient, das Konzept zu beschreiben, hat es keine so gute Verteilung, wie man es gerne hätte. Natürlich, wenn man so etwas bereits implementiert hat, kann man es nicht ändern, ohne die Garantie zu brechen, aber wenn ich jetzt empfehlen würde Diese Bibliothek von mir, geschrieben nach der Forschung wie folgt:

%Vor%

Das für RandomComparer oben ist nicht so schlimm, aber kann auch verbessert werden:

%Vor%

Oder für noch bessere Vorhersagbarkeit:

%Vor%     
Jon Hanna 12.01.2012, 17:21
quelle
1

Es wird in verschiedenen Läufen sogar auf demselben Computer unterschiedliche Ergebnisse erzeugen.

Es kann also grundsätzlich verwendet werden (und es wird tatsächlich verwendet), um etwas während des aktuellen Laufs des Programms zu überprüfen, aber es gibt keinen Sinn es zu speichern, um danach etwas dagegen zu prüfen. Ursache Die Nummer, die Sie erhalten, wird von Laufzeit generiert.

BEARBEITEN

Für den spezifischen Fall einer Zeichenkette wird das gleiche Ergebnis auch auf verschiedenen Rechnern erzeugt, außer wenn die Maschinen eine andere Architektur haben.

    
Tigran 12.01.2012 15:59
quelle

Tags und Links