Object.GetHashCode Methode

Definition

Dient als Standardhashfunktion.

public:
 virtual int GetHashCode();
public virtual int GetHashCode();
abstract member GetHashCode : unit -> int
override this.GetHashCode : unit -> int
Public Overridable Function GetHashCode () As Integer

Gibt zurück

Ein Hashcode für das aktuelle Objekt.

Beispiele

Eine der einfachsten Methoden zum Berechnen eines Hashcodes für einen numerischen Wert mit demselben oder einem kleineren Bereich als der Int32 Typ besteht darin, einfach diesen Wert zurückzugeben. Das folgende Beispiel zeigt eine solche Implementierung für eine Number Struktur.

using System;

public struct Number
{
   private int n;

   public Number(int value)
   {
      n = value;
   }

   public int Value
   {
      get { return n; }
   }

   public override bool Equals(Object obj)
   {
      if (obj == null || ! (obj is Number))
         return false;
      else
         return n == ((Number) obj).n;
   }

   public override int GetHashCode()
   {
      return n;
   }

   public override string ToString()
   {
      return n.ToString();
   }
}

public class Example1
{
   public static void Main()
   {
      Random rnd = new Random();
      for (int ctr = 0; ctr <= 9; ctr++) {
         int randomN = rnd.Next(Int32.MinValue, Int32.MaxValue);
         Number n = new Number(randomN);
         Console.WriteLine("n = {0,12}, hash code = {1,12}", n, n.GetHashCode());
      }
   }
}
// The example displays output like the following:
//       n =   -634398368, hash code =   -634398368
//       n =   2136747730, hash code =   2136747730
//       n =  -1973417279, hash code =  -1973417279
//       n =   1101478715, hash code =   1101478715
//       n =   2078057429, hash code =   2078057429
//       n =   -334489950, hash code =   -334489950
//       n =    -68958230, hash code =    -68958230
//       n =   -379951485, hash code =   -379951485
//       n =    -31553685, hash code =    -31553685
//       n =   2105429592, hash code =   2105429592
open System

[<Struct; CustomEquality; NoComparison>]
type Number(value: int) =
    member _.Value = value

    override _.Equals(obj) =
        match obj with
        | :? Number as n ->
            n.Value = value
        | _ -> false

    override _.GetHashCode() =
        value

    override _.ToString() =
        string value

let rnd = Random()
for _ = 0 to 9 do
    let randomN = rnd.Next(Int32.MinValue, Int32.MaxValue)
    let n = Number randomN
    printfn $"n = {n,12}, hash code = {n.GetHashCode(),12}"
// The example displays output like the following:
//       n =   -634398368, hash code =   -634398368
//       n =   2136747730, hash code =   2136747730
//       n =  -1973417279, hash code =  -1973417279
//       n =   1101478715, hash code =   1101478715
//       n =   2078057429, hash code =   2078057429
//       n =   -334489950, hash code =   -334489950
//       n =    -68958230, hash code =    -68958230
//       n =   -379951485, hash code =   -379951485
//       n =    -31553685, hash code =    -31553685
//       n =   2105429592, hash code =   2105429592
Public Structure Number
   Private n As Integer

   Public Sub New(value As Integer)
      n = value
   End Sub

   Public ReadOnly Property Value As Integer
      Get
         Return n
      End Get
   End Property
   
   Public Overrides Function Equals(obj As Object) As Boolean
      If obj Is Nothing OrElse Not TypeOf obj Is Number Then
         Return False
      Else
         Return n = CType(obj, Number).n
      End If
   End Function      
   
   Public Overrides Function GetHashCode() As Integer
      Return n
   End Function
   
   Public Overrides Function ToString() As String
      Return n.ToString()
   End Function
End Structure

Module Example1
    Public Sub Main()
        Dim rnd As New Random()
        For ctr As Integer = 0 To 9
            Dim randomN As Integer = rnd.Next(Int32.MinValue, Int32.MaxValue)
            Dim n As New Number(randomN)
            Console.WriteLine("n = {0,12}, hash code = {1,12}", n, n.GetHashCode())
        Next
    End Sub
End Module
' The example displays output like the following:
'       n =   -634398368, hash code =   -634398368
'       n =   2136747730, hash code =   2136747730
'       n =  -1973417279, hash code =  -1973417279
'       n =   1101478715, hash code =   1101478715
'       n =   2078057429, hash code =   2078057429
'       n =   -334489950, hash code =   -334489950
'       n =    -68958230, hash code =    -68958230
'       n =   -379951485, hash code =   -379951485
'       n =    -31553685, hash code =    -31553685
'       n =   2105429592, hash code =   2105429592

Häufig verfügt ein Typ über mehrere Datenfelder, die an der Generierung des Hashcodes teilnehmen können. Eine Möglichkeit zum Generieren eines Hashcodes besteht darin, diese Felder mithilfe eines XOR (eXclusive OR) Vorgangs zu kombinieren, wie im folgenden Beispiel gezeigt.

using System;

// A type that represents a 2-D point.
public struct Point2
{
    private int x;
    private int y;

    public Point2(int x, int y)
    {
       this.x = x;
       this.y = y;
    }

    public override bool Equals(Object obj)
    {
       if (! (obj is Point2)) return false;

       Point2 p = (Point2) obj;
       return x == p.x & y == p.y;
    }

    public override int GetHashCode()
    {
        return x ^ y;
    }
}

public class Example3
{
   public static void Main()
   {
      Point2 pt = new Point2(5, 8);
      Console.WriteLine(pt.GetHashCode());

      pt = new Point2(8, 5);
      Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays the following output:
//       13
//       13
// A type that represents a 2-D point.
[<Struct; CustomEquality; NoComparison>]
type Point(x: int, y: int) =
    member _.X = x
    member _.Y = y

    override _.Equals(obj) =
        match obj with
        | :? Point as p ->
            x = p.X && y = p.Y
        | _ ->
            false

    override _.GetHashCode() =
        x ^^^ y

let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"

let pt2 = Point(8, 5)
printfn $"{pt2.GetHashCode()}"

// The example displays the following output:
//       13
//       13
' A type that represents a 2-D point.
Public Structure Point3
    Private x As Integer
    Private y As Integer

    Public Sub New(x As Integer, y As Integer)
        Me.x = x
        Me.y = y
    End Sub

    Public Overrides Function Equals(obj As Object) As Boolean
        If Not TypeOf obj Is Point3 Then Return False

        Dim p As Point3 = CType(obj, Point3)
        Return x = p.x And y = p.y
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return x Xor y
    End Function
End Structure

Public Module Example3
    Public Sub Main()
        Dim pt As New Point3(5, 8)
        Console.WriteLine(pt.GetHashCode())

        pt = New Point3(8, 5)
        Console.WriteLine(pt.GetHashCode())
    End Sub
End Module

Im vorherigen Beispiel wird derselbe Hashcode für (n1, n2) und (n2, n1) zurückgegeben, sodass möglicherweise mehr Kollisionen generiert werden, als wünschenswert sind. Auf .NET 5+ ist die empfohlene Lösung zu verwenden HashCode.Combine. Es vermeidet das Symmetrieproblem und erzeugt einen gut verteilten Hashcode ohne den Aufwand der Erstellung eines Tuple Objekts.

using System;

public struct Point3
{
    private int x;
    private int y;

    public Point3(int x, int y)
    {
       this.x = x;
       this.y = y;
    }

    public override bool Equals(Object obj)
    {
        if (obj is Point3)
        {
            Point3 p = (Point3) obj;
            return x == p.x & y == p.y;
        }
        else
        {
            return false;
        }      
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(x, y);
    }
}

public class Example
{
   public static void Main()
   {
        Point3 pt = new Point3(5, 8);
        Console.WriteLine(pt.GetHashCode());

        pt = new Point3(8, 5);
        Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays output similar to the following.
// Note: HashCode.Combine results are not stable across .NET versions.
//       185727722
//       -363254492
[<Struct; CustomEquality; NoComparison>]
type Point(x: int, y: int) =
    member _.X = x
    member _.Y = y

    override _.Equals(obj) =
        match obj with
        | :? Point as p ->
            x = p.X && y = p.Y
        | _ -> 
            false

    override _.GetHashCode() =
        System.HashCode.Combine(x, y)

let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"

let pt2 = Point(8, 5)
printfn $"{pt2.GetHashCode()}"
// The example displays output similar to the following.
// Note: HashCode.Combine results are not stable across .NET versions.
//       185727722
//       -363254492
Public Structure Point
    Private x As Integer
    Private y As Integer

    Public Sub New(x As Integer, y As Integer)
       Me.x = x
       Me.y = y
    End Sub
    
    Public Overrides Function Equals(obj As Object) As Boolean
       If Not TypeOf obj Is Point Then Return False
       
       Dim p As Point = CType(obj, Point)
       Return x = p.x And y = p.y
    End Function
    
    Public Overrides Function GetHashCode() As Integer 
        Return HashCode.Combine(x, y)
    End Function 
End Structure 

Public Module Example
    Public Sub Main() 
        Dim pt As New Point(5, 8)
        Console.WriteLine(pt.GetHashCode())
        
        pt = New Point(8, 5)
        Console.WriteLine(pt.GetHashCode())
    End Sub 
End Module         
' The example displays output similar to the following.
' Note: HashCode.Combine results are not stable across .NET versions.
'       185727722
'       -363254492

Hinweise

Die GetHashCode Methode stellt einen Hashcode für Algorithmen bereit, die schnelle Überprüfungen der Objektgleichheit benötigen. Ein Hashcode ist ein numerischer Wert, der zum Einfügen und Identifizieren eines Objekts in einer hashbasierten Auflistung verwendet wird, z. B. die Dictionary<TKey,TValue> Klasse, die Hashtable Klasse oder einen von der DictionaryBase Klasse abgeleiteten Typ.

Note

Informationen dazu, wie Hashcodes in Hashtabellen und für einige zusätzliche Hashcodealgorithmen verwendet werden, finden Sie im Eintrag "Hash function " in Wikipedia.

Zwei Objekte, die gleich sind, erzeugen gleiche Hashcodes. Die Umgekehrte ist jedoch nicht wahr: Gleiche Hashcodes implizieren keine Objektgleichheit, da verschiedene (ungleiche) Objekte identische Hashcodes aufweisen können. Darüber hinaus garantiert .NET nicht die Standardimplementierung der GetHashCode-Methode, und der Wert, den diese Methode zurückgibt, kann sich zwischen .NET Implementierungen und Plattformen unterscheiden, z. B. zwischen 32-Bit- und 64-Bit-Plattformen. Verwenden Sie aus diesen Gründen die Standardimplementierung dieser Methode nicht als eindeutigen Objektbezeichner für Hashing-Zwecke. Daraus folgen zwei Folgen:

  • Sie sollten nicht davon ausgehen, dass gleiche Hashcodes die Objektgleichheit implizieren.
  • Sie sollten niemals einen Hashcode außerhalb der Anwendungsdomäne beibehalten oder verwenden, in der sie erstellt wurde, da dasselbe Objekt einen Hash über Anwendungsdomänen, Prozesse und Plattformen hinweg ausführen kann.

Warning

Ein Hashcode dient zum effizienten Einfügen und Nachschlagen in Auflistungen, die auf einer Hashtabelle basieren. Ein Hashcode ist kein dauerhafter Wert. Aus diesem Grund:

  • Serialisieren Sie keine Hashcodewerte, oder speichern Sie sie in Datenbanken.
  • Verwenden Sie den Hashcode nicht als Schlüssel, um ein Objekt aus einer keyed-Auflistung abzurufen.
  • Senden Sie Hashcodes nicht über Anwendungsdomänen oder Prozesse hinweg. In einigen Fällen können Hashcodes pro Prozess oder Anwendungsdomäne berechnet werden.
  • Verwenden Sie nicht den Hashcode anstelle eines Werts, der von einer kryptografischen Hashfunktion zurückgegeben wird, wenn Sie einen kryptografisch starken Hash benötigen. Verwenden Sie für kryptografische Hashes eine von der System.Security.Cryptography.HashAlgorithm Oder-Klasse System.Security.Cryptography.KeyedHashAlgorithm abgeleitete Klasse.
  • Vermeiden Sie es, die Gleichheit von Hashcodes zu prüfen, um festzustellen, ob zwei Objekte gleich sind. (Ungleiche Objekte können identische Hashcodes aufweisen.) Um die Gleichheit zu testen, rufen Sie die ReferenceEquals- oder Equals-Methode auf.

Die GetHashCode-Methode kann von einem abgeleiteten Typ überschrieben werden. Wenn GetHashCode nicht außer Kraft gesetzt wird, werden Hashcodes für Referenztypen durch Aufrufen der Object.GetHashCode Methode der Basisklasse berechnet, die einen Hashcode basierend auf dem Verweis eines Objekts berechnet. Weitere Informationen finden Sie unter RuntimeHelpers.GetHashCode. Mit anderen Worten, zwei Objekte, für die die Methode ReferenceEquals den Wert true zurückgibt, haben identische Hashcodes. Wenn Wertetypen GetHashCode nicht überschreiben, verwendet die ValueType.GetHashCode-Methode der Basisklasse Reflection, um den Hash-Code auf der Grundlage der Werte der Felder des Typs zu berechnen. Mit anderen Worten: Werttypen, deren Felder gleich Werte haben, weisen gleiche Hashcodes auf. Weitere Informationen zum Überschreiben von GetHashCode, finden Sie im Abschnitt "Hinweise für Erben".

Warning

Wenn Sie die GetHashCode Methode überschreiben, sollten Sie auch die Equals Methode überschreiben und umgekehrt. Wenn Ihre überschreibende Equals-Methode true zurückgibt, wenn zwei Objekte auf Gleichheit getestet werden, muss Ihre überschreibende GetHashCode-Methode denselben Wert für die beiden Objekte zurückgeben.

Wenn ein Objekt, das als Schlüssel in einer Hashtabelle verwendet wird, keine nützliche Implementierung GetHashCodebereitstellt, können Sie einen Hashcodeanbieter angeben, indem Sie eine IEqualityComparer Implementierung für eine der Überladungen des Hashtable Klassenkonstruktors bereitstellen.

Hinweise für Vererber

Eine Hashfunktion wird verwendet, um schnell eine Zahl (Hashcode) zu generieren, die dem Wert eines Objekts entspricht. Hashfunktionen sind in der Regel für jeden Typ spezifisch und müssen für die Eindeutigkeit mindestens eines der Instanzfelder als Eingabe verwenden. Hashcodes sollten nicht mithilfe der Werte statischer Felder berechnet werden.

Bei klassen, die von Objectabgeleitet werden, kann die GetHashCode Methode nur dann an die Basisklassenimplementierung GetHashCode() delegiert werden, wenn die abgeleitete Klasse die Gleichheit definiert, die als Referenzgleichheit gilt. Die Standardimplementierung für GetHashCode() Referenztypen gibt einen Hashcode zurück, der dem von der GetHashCode(Object) Methode zurückgegebenen entspricht. Sie können für unveränderliche Verweistypen außer Kraft setzen GetHashCode() . Im Allgemeinen sollten Sie für veränderbare Referenztypen nur dann außer Kraft setzen GetHashCode() , wenn:

  • Sie können den Hashcode aus Feldern berechnen, die nicht änderbar sind. Oder

  • Sie können sicherstellen, dass sich der Hashcode eines veränderbaren Objekts nicht ändert, während das Objekt in einer Auflistung enthalten ist, die auf seinem Hashcode basiert.

Andernfalls denken Sie vielleicht, dass das veränderbare Objekt in der Hashtabelle verloren geht. Wenn Sie sich dafür entscheiden, einen veränderbaren Verweistyp außer Kraft GetHashCode() zu setzen, sollte ihre Dokumentation deutlich machen, dass Benutzer Ihres Typs objektwerte nicht ändern sollten, während das Objekt in einer Hashtabelle gespeichert ist.

Stellt für Werttypen eine standardmäßige Hashcodeimplementierung bereit, GetHashCode() die Spiegelung verwendet. Sie sollten erwägen, sie für eine bessere Leistung außer Kraft zu setzen.

Weitere Informationen und Beispiele, die Hashcodes auf unterschiedliche Weise berechnen, finden Sie im Abschnitt "Beispiele".

Eine Hashfunktion muss über die folgenden Eigenschaften verfügen:

  • Wenn zwei Objekte gleich vergleichen, muss die GetHashCode() Methode für jedes Objekt denselben Wert zurückgeben. Wenn zwei Objekte jedoch nicht gleich verglichen werden, müssen die GetHashCode() Methoden für die beiden Objekte keine unterschiedlichen Werte zurückgeben.

  • Die GetHashCode() Methode für ein Objekt muss konsistent denselben Hashcode zurückgeben, solange keine Änderung am Objektzustand vorhanden ist, die den Rückgabewert der System.Object.Equals-Methode des Objekts bestimmt. Beachten Sie, dass dies nur für die aktuelle Ausführung einer Anwendung gilt und dass ein anderer Hashcode zurückgegeben werden kann, wenn die Anwendung erneut ausgeführt wird.

  • Um eine optimale Leistung zu erzielen, sollte eine Hashfunktion eine gleichmäßige Verteilung für alle Eingaben generieren, einschließlich der eingabe, die stark gruppiert ist. Eine Auswirkung ist, dass kleine Änderungen am Objektzustand zu großen Änderungen am resultierenden Hashcode führen sollten, um eine optimale Leistung der Hashtabelle zu erzielen.

  • Hashfunktionen sollten kostengünstig zu berechnen sein.

  • Die GetHashCode() Methode sollte keine Ausnahmen auslösen.

Die Implementierung der GetHashCode() von der String Klasse bereitgestellten Methode gibt beispielsweise identische Hashcodes für identische Zeichenfolgenwerte zurück. Daher geben zwei String Objekte denselben Hashcode zurück, wenn sie denselben Zeichenfolgenwert darstellen. Außerdem verwendet die Methode alle Zeichen in der Zeichenfolge, um eine relativ zufällig verteilte Ausgabe zu generieren, auch wenn die Eingabe in bestimmten Bereichen gruppiert ist (z. B. viele Benutzer verfügen möglicherweise über Zeichenfolgen, die nur die unteren 128 ASCII-Zeichen enthalten, auch wenn eine Zeichenfolge eine der 65.535 Unicode-Zeichen enthalten kann).

Die Bereitstellung einer guten Hashfunktion für eine Klasse kann die Leistung des Hinzufügens dieser Objekte zu einer Hashtabelle erheblich beeinträchtigen. Bei einer Hashtabelle mit Schlüsseln, die eine gute Implementierung einer Hashfunktion bereitstellen, dauert die Suche nach einem Element konstante Zeit (z. B. ein O(1)-Vorgang). In einer Hashtabelle mit einer schlechten Implementierung einer Hashfunktion hängt die Leistung einer Suche von der Anzahl der Elemente in der Hashtabelle ab (z. B. ein O(n)-Vorgang, wobei n die Anzahl der Elemente in der Hashtabelle angegeben ist. Ein böswilliger Benutzer kann Daten eingeben, die die Anzahl der Kollisionen erhöhen, was die Leistung von Anwendungen erheblich beeinträchtigen kann, die von Hashtabellen abhängig sind, unter den folgenden Bedingungen:

  • Wenn Hashfunktionen häufige Kollisionen erzeugen.

  • Wenn ein großer Teil von Objekten in einer Hashtabelle Hashcodes erzeugt, die gleich oder ungefähr gleicheinander sind.

  • Wenn Benutzer die Daten eingeben, aus denen der Hashcode berechnet wird.

Abgeleitete Klassen, die außer Kraft GetHashCode() setzen, müssen auch außer Kraft setzen Equals(Object) , um sicherzustellen, dass zwei Objekte, die als gleich angesehen werden, denselben Hashcode aufweisen. Andernfalls funktioniert der Hashtable Typ möglicherweise nicht ordnungsgemäß.

Gilt für:

Weitere Informationen