2008-09-09 3 views

Antwort

29

Wenn ich mich nicht irre, ist GetHashCode konsistent mit dem gleichen Wert, aber es ist NICHT garantiert, dass es über verschiedene Versionen des Frameworks konsistent ist.

Aus den MSDN-Dokumentation auf String.GetHashCode():

Das Verhalten von GetHashCode ist abhängig von seiner Implementierung, die von einer Version der Common Language Runtime zum anderen ändern kann. Ein Grund, warum dies passieren könnte, ist, die Leistung von GetHashCode zu verbessern.

+1

Fazit: Nie persistieren oder das Ergebnis von 'GetHashCode()' übertragen. Verwenden Sie es nur für den vorgesehenen Zweck: um die Verwendung von Hashtabellen zu erleichtern. –

0

Ich frage mich, ob es Unterschiede zwischen 32-Bit- und 64-Bit-Betriebssystemen, weil ich sicher bin, sowohl mein Server und Computer zu Hause sind, die gleiche Version von .NET

Laufen war ich immer müde Mit GetHashCode() könnte es eine gute Idee sein, einfach meinen eigenen Hash-Algorithmus zu verwenden. Naja, zumindest habe ich am Ende eine schnelle Index-ASPX-Seite geschrieben.

0

Verwenden Sie Win2008 x86 als Ihren Desktop? Da Win2008 die Version 2.0.50727.1434 enthält, ist dies eine aktualisierte Version von 2.0, die in Vista RTM enthalten ist.

0

keine direkte Antwort auf Ihre Frage, die Jonas gut beantwortet hat, was jedoch von Nutzen sein kann, wenn Sie in Hashes Sorgen um Gleichheit Tests sind

Von unseren Tests, je nachdem, was Sie mit Hashcodes erfordern, In C# müssen Hashcodes für Gleichheitsoperationen nicht eindeutig sein. Als Beispiel betrachten wir folgendes:

Wir hatten eine Anforderung, den Gleichheitsoperator und damit die GetHashCode-Funktion unserer Objekte zu überlasten, da sie flüchtig und zustandslos geworden waren, und sich direkt aus Daten, also an einer Stelle, von Quellen die Anwendung, die wir benötigten, um sicherzustellen, dass ein Objekt als gleich einem anderen Objekt angesehen würde, wenn es aus den gleichen Daten stammte, nicht nur, wenn es die gleiche Referenz war. Unsere eindeutigen Datenkennungen sind Guids.

Der Gleichheitsoperator war einfach zu bedienen, da wir nur auf die Guid des Datensatzes überprüft (nach der Überprüfung auf Null).

Leider ist die HashCode-Datengröße (die ein int ist) abhängig vom Betriebssystem und auf unserem 32-Bit-System wäre der Hashcode 32 Bit. Wenn wir die GetHashCode-Funktion überschreiben, ist es mathematisch unmöglich, aus einer GUID, die größer als 32 Bit ist, einen eindeutigen Hashcode zu generieren (schauen Sie sich die Converse an, wie würden Sie eine 32-Bit-Ganzzahl in eine GUID übersetzen).

Wir haben dann einige Tests durchgeführt, bei denen wir Guid als String genommen haben und den HashCode des Guid zurückgegeben haben, der in unseren Tests fast immer einen eindeutigen Bezeichner liefert, aber nicht immer.

Was wir jedoch festgestellt haben, wenn ein Objekt in einem Hashed-Collection-Objekt ist (eine Hashtabelle, ein Dictionary usw.), wenn 2 Objekte nicht eindeutig sind, aber ihre Hashcodes sind, wird der Hashcode nur als erste Option verwendet. Wenn nicht eindeutige Hash-Codes verwendet werden, wird der Gleichheitsoperator immer als ein Fall verwendet, der auf Gleichheit zurückgeht.

Wie ich schon sagte, kann dies für Ihre Situation relevant sein oder nicht, aber wenn es das ist, ist es ein praktischer Tipp.

UPDATE

zu demonstrieren, haben wir eine Hashtable:

Key: Object Ein (Hashcode 1),

A1 Wert Objekt

Key: Objekt B (Hashcode 1), Wert Object B1

Key: Object C (Hashcode 1), den Wert Object C1

Key: Object D (Hashcode 2), den Wert Ob jekt D1

Key: Object E (Hashcode 3), Wert Objekt E1

Wenn ich die Hash-Tabelle für das Objekt mit dem Schlüssel des Objekts A nennen, wird das Objekt A1 nach 2 Stufen zurückgeführt werden, ein Anruf für hashcode 1, dann eine Gleichheitsprüfung auf dem Schlüssel-Objekt, da es mit dem Hash-Code 1

als ich rufe Sie die Hash-Tabelle für das Objekt mit dem Schlüssel des Objekt D keinen eindeutiger Schlüssel ist, wird das Objekt D1 nach dem 1. Schritt zurück , ein Hash-Lookup

0

Was wir jedoch bemerkt haben, wenn eine Objekt ist in einem Hash-Sammlung Objekt (eine Hash-Tabelle, ein Wörterbuch usw.), wenn zwei Objekte nicht eindeutig zuzuordnen sind aber ihre Hashcodes sind, die hashcode nur als erste Option Lookup verwendet wird, wenn es nicht eindeutig Hash-Codes verwendet wird, wird der Gleichheitsoperator immer als ein Fall zurück zu Gleichheit Gleichheit verwendet.

So funktionieren Hash-Lookups, richtig? Jeder Bucket enthält eine Liste von Elementen mit demselben Hash-Code.

Um also unter diesen Bedingungen das richtige Element zu finden, wird eine lineare Suche mit Vergleich der Wertegleichheit durchgeführt.

Und wenn Ihre Hashing-Implementierung eine gute Verteilung erreicht, ist diese Suche nicht erforderlich, d. H. Ein Element pro Bucket.

Ist mein Verständnis korrekt?

+0

Ben, aus unserem Test, das ist wahr. Die zweite Gleichheitssuche läuft nur wie benötigt. Sie können es selbst testen, indem Sie das ==,! =, Equals() und GetHashCode eines bestimmten Objekts überladen. Ich fand es sehr interessant (aber ich bin ein Geek :)) – johnc

+0

(Fortsetzung), so wäre die Wirkung von nicht-einstimmigen Hash-Codes Leistung langsamer, um die Gleichheitsprüfung zu laufen, aber in unserer Situation, wo der nichtunique Wert sehr selten ist, es ist weitgehend unbedeutend – johnc

5

Die Implementierung hängt von der Version des Frameworks ab, hängt aber auch von architecture ab. Die Implementierung von string.GetHashCode() ist in den x86- und x64-Versionen des Frameworks auch dann different, wenn sie dieselbe Versionsnummer haben.

10

Ich hatte ein ähnliches Problem, wo ich eine Datenbanktabelle mit Informationen füllte, die von String.GetHashCode abhängig waren (nicht die beste Idee) und als ich den Server verbesserte, den ich an x64 arbeitete, bemerkte ich die Werte, die ich erhielt Zeichenfolge.GetHashCode stimmte nicht mit dem überein, was bereits in der Tabelle war. Meine Lösung war, meine eigene Version von GetHashCode zu verwenden, die denselben Wert wie String.GetHashCode auf einem x86-Framework zurückgibt.

Hier ist der Code, vergessen Sie nicht, mit „Erlauben unsicheren Code“ zu kompilieren:

/// <summary> 
    /// Similar to String.GetHashCode but returns the same as the x86 version of String.GetHashCode for x64 and x86 frameworks. 
    /// </summary> 
    /// <param name="s"></param> 
    /// <returns></returns> 
    public static unsafe int GetHashCode32(string s) 
    { 
     fixed (char* str = s.ToCharArray()) 
     { 
      char* chPtr = str; 
      int num = 0x15051505; 
      int num2 = num; 
      int* numPtr = (int*)chPtr; 
      for (int i = s.Length; i > 0; i -= 4) 
      { 
       num = (((num << 5) + num) + (num >> 0x1b))^numPtr[0]; 
       if (i <= 2) 
       { 
        break; 
       } 
       num2 = (((num2 << 5) + num2) + (num2 >> 0x1b))^numPtr[1]; 
       numPtr += 2; 
      } 
      return (num + (num2 * 0x5d588b65)); 
     } 
    } 
+1

Ich hatte das gleiche Problem und portierte Ihre Version auf eine sichere Methode. https://gist.github.com/gerritze/7542231#file-gethashcode32-net –

-1

Ich würde sagen ... Sie nicht auf sie verlassen können. Zum Beispiel, wenn ich file1 bis C# 's md5-Hash-Code laufen lasse und die gleiche Datei in ein neues Verzeichnis kopiere und einfügen würde ... der Hash-Code würde sich unterscheiden, auch wenn es die gleiche Datei ist. Offensichtlich ist es die gleiche .net Version, alles gleich. Das einzige, was sich geändert hat, war der Weg.

1
/// <summary> 
    /// Default implementation of string.GetHashCode is not consistent on different platforms (x32/x64 which is our case) and frameworks. 
    /// FNV-1a - (Fowler/Noll/Vo) is a fast, consistent, non-cryptographic hash algorithm with good dispersion. (see http://isthe.com/chongo/tech/comp/fnv/#FNV-1a) 
    /// </summary> 
    private static int GetFNV1aHashCode(string str) 
    { 
     if (str == null) 
      return 0; 
     var length = str.Length; 
     // original FNV-1a has 32 bit offset_basis = 2166136261 but length gives a bit better dispersion (2%) for our case where all the strings are equal length, for example: "3EC0FFFF01ECD9C4001B01E2A707" 
     int hash = length; 
     for (int i = 0; i != length; ++i) 
      hash = (hash^str[i]) * 16777619; 
     return hash; 
    } 

Diese Implementierung kann langsamer sein als die unsichere, die vorher gepostet wurde. Aber viel einfacher und sicherer.

Verwandte Themen