72 Stimmen

Wie implementieren Sie GetHashCode für Struktur mit zwei Zeichenfolgen, wenn beide Zeichenfolgen austauschbar sind

Ich habe eine Struktur in C#:

public struct UserInfo
{
   public string str1
   {
     get;
     set;
   }

   public string str2
   {
     get;
     set;
   }   
}

Die einzige Regel ist, dass UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))

Wie kann die Funktion GetHashCode für diese Struktur überschrieben werden?

71voto

aku Punkte 118808

MSDN :

Eine Hash-Funktion muss die folgenden Eigenschaften haben:

  • Wenn zwei Objekte als gleichwertig verglichen werden, wird die GetHashCode Methode muss für jedes Objekt den gleichen Wert zurückgeben. Wenn jedoch zwei Objekte nicht als gleichwertig verglichen werden können, muss die GetHashCode Methoden für die beiden Objekte müssen nicht unterschiedliche Werte zurückgeben.
  • があります。 GetHashCode Methode für ein Objekt muss stets denselben Hash-Code zurückgeben, solange keine Änderung des Objektzustands erfolgt, die den Rückgabewert der Objektmethode Equals Methode. Beachten Sie, dass dies nur für die aktuelle Ausführung einer Anwendung gilt und dass ein anderer Hash-Code zurückgegeben werden kann, wenn die Anwendung erneut ausgeführt wird.
  • Um die beste Leistung zu erzielen, muss eine Hash-Funktion eine Zufallsverteilung für alle Eingaben erzeugen.

Richtig ist die Berücksichtigung:

return str1.GetHashCode() ^ str2.GetHashCode() 

^ kann durch eine andere kommutative Operation ersetzt werden

27voto

Tomáš Kafka Punkte 3930

Véase Antwort von Jon Skeet - binäre Operationen wie ^ sind nicht gut, da sie oft kollidierende Hashs erzeugen!

16voto

public override int GetHashCode()
{
    unchecked
    {
        return (str1 ?? String.Empty).GetHashCode() +
            (str2 ?? String.Empty).GetHashCode();
    }
}

Die Verwendung des Operators '+' könnte besser sein als die Verwendung von '^', denn obwohl Sie ausdrücklich wollen, dass ('AA', 'BB') und ('BB', 'AA') gleich sind, wollen Sie vielleicht nicht, dass ('AA', 'AA') und ('BB', 'BB') gleich sind (oder alle gleichen Paare, was das betrifft).

Die Regel "so schnell wie möglich" wird bei dieser Lösung nicht ganz eingehalten, da im Falle von Nullen ein "GetHashCode()" auf der leeren Zeichenkette ausgeführt wird, anstatt sofort eine bekannte Konstante zurückzugeben, aber auch ohne explizite Messung bin ich bereit, die Vermutung zu wagen, dass der Unterschied nicht groß genug wäre, um sich Sorgen zu machen, es sei denn, Sie erwarten viele Nullen.

5voto

Joe Punkte 117971
  1. Im Allgemeinen besteht eine einfache Möglichkeit, einen Hashcode für eine Klasse zu generieren, in der XOR-Verknüpfung aller Datenfelder, die an der Generierung des Hashcodes beteiligt sein können (wobei darauf zu achten ist, dass sie auf Null geprüft werden, wie von anderen bereits erwähnt). Dies erfüllt auch die (künstliche?) Anforderung, dass die Hashcodes für UserInfo("AA", "BB") und UserInfo("BB", "AA") identisch sind.

  2. Wenn Sie Annahmen über die Verwendung Ihrer Klasse machen können, können Sie vielleicht Ihre Hash-Funktion verbessern. Wenn es beispielsweise üblich ist, dass str1 und str2 gleich sind, ist XOR vielleicht keine gute Wahl. Wenn str1 und str2 aber z. B. Vor- und Nachname darstellen, ist XOR wahrscheinlich eine gute Wahl.

Auch wenn es sich hier nicht um ein Beispiel aus der Praxis handelt, sollte man vielleicht darauf hinweisen: - Dies ist wahrscheinlich ein schlechtes Beispiel für die Verwendung einer Struktur: Eine Struktur sollte normalerweise eine Wertesemantik haben, was hier nicht der Fall zu sein scheint. - Die Verwendung von Eigenschaften mit Settern, um einen Hash-Code zu erzeugen, birgt ebenfalls Probleme.

4voto

Daniel Lidström Punkte 8778

Eine einfache allgemein Weg ist dies zu tun:

return string.Format("{0}/{1}", str1, str2).GetHashCode();

Sofern Sie keine strengen Leistungsanforderungen haben, ist dies die einfachste Methode, die ich mir vorstellen kann, und ich verwende diese Methode häufig, wenn ich einen zusammengesetzten Schlüssel benötige. Sie behandelt die null Fälle sehr gut und verursachen (m)eine Hash-Kollision (im Allgemeinen) nicht. Wenn Sie '/' in Ihren Strings erwarten, wählen Sie einfach ein anderes Trennzeichen, das Sie nicht erwarten.

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