Object.GetHashCode Methode
Definition
Wichtig
Einige Informationen beziehen sich auf Vorabversionen, die vor dem Release ggf. grundlegend überarbeitet werden. Microsoft übernimmt hinsichtlich der hier bereitgestellten Informationen keine Gewährleistungen, seien sie ausdrücklich oder konkludent.
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äß.