Object.GetHashCode Methode
Definitie
Belangrijk
Bepaalde informatie heeft betrekking op een voorlopige productversie die aanzienlijk kan worden gewijzigd voordat deze wordt uitgebracht. Microsoft biedt geen enkele expliciete of impliciete garanties met betrekking tot de informatie die hier wordt verstrekt.
Fungeert als de standaardhashfunctie.
public:
virtual int GetHashCode();
public virtual int GetHashCode();
abstract member GetHashCode : unit -> int
override this.GetHashCode : unit -> int
Public Overridable Function GetHashCode () As Integer
Retouren
Een hashcode voor het huidige object.
Voorbeelden
Een van de eenvoudigste manieren om een hashcode te berekenen voor een numerieke waarde die hetzelfde of een kleiner bereik heeft dan het Int32 type, is om die waarde te retourneren. In het volgende voorbeeld ziet u een dergelijke implementatie voor een Number structuur.
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
Vaak heeft een type meerdere gegevensvelden die kunnen deelnemen aan het genereren van de hash-code. Een manier om een hashcode te genereren, is door deze velden te combineren met behulp van een XOR (eXclusive OR) bewerking, zoals wordt weergegeven in het volgende voorbeeld.
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
In het vorige voorbeeld wordt dezelfde hash-code geretourneerd voor (n1, n2) en (n2, n1), waardoor er mogelijk meer conflicten ontstaan dan wenselijk is. Op .NET 5+ is de aanbevolen oplossing te gebruiken HashCode.Combine. Het voorkomt het symmetrieprobleem en produceert een goed gedistribueerde hash-code zonder de overhead van het maken van een Tuple object.
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
Opmerkingen
De GetHashCode methode biedt een hash-code voor algoritmen die snelle controles van object gelijkheid nodig hebben. Een hash-code is een numerieke waarde die wordt gebruikt om een object in te voegen en te identificeren in een op hash gebaseerde verzameling, zoals de Dictionary<TKey,TValue> klasse, de Hashtable klasse of een type dat is afgeleid van de DictionaryBase klasse.
Opmerking
Zie de vermelding Hash-functie in Wikipedia voor informatie over hoe hash-codes worden gebruikt in hashtabellen en voor een aantal extra hashcodealgoritmen.
Twee objecten die gelijk zijn, geven hashcodes die gelijk zijn. Het omgekeerde is echter niet waar: gelijke hashcodes impliceren geen objectgelijkheid, omdat verschillende (ongelijke) objecten identieke hashcodes kunnen hebben. Bovendien garandeert .NET niet de standaard implementatie van de methode GetHashCode, en de waarde die deze methode retourneert, kan verschillen tussen .NET implementaties en platforms, zoals tussen 32-bits en 64-bits platforms. Gebruik om deze redenen de standaard implementatie van deze methode niet als een unieke object-id voor hash-doeleinden. Hier volgen twee gevolgen:
- U mag er niet van uitgaan dat gelijke hash-codes objectgelijkheid impliceren.
- U moet nooit een hash-code behouden of gebruiken buiten het toepassingsdomein waarin het is gemaakt, omdat hetzelfde object kan hashen tussen toepassingsdomeinen, processen en platforms.
Warning
Een hash-code is bedoeld voor efficiënte invoeging en zoekactie in verzamelingen die zijn gebaseerd op een hash-tabel. Een hash-code is geen permanente waarde. Om deze reden:
- Serialiseer geen hashcodewaarden of sla deze op in databases.
- Gebruik de hashcode niet als sleutel om een object op te halen uit een sleutelverzameling.
- Verzend geen hash-codes tussen toepassingsdomeinen of processen. In sommige gevallen kunnen hashcodes worden berekend per proces of per toepassingsdomein.
- Gebruik de hash-code niet in plaats van een waarde die wordt geretourneerd door een cryptografische hashfunctie als u een cryptografische sterke hash nodig hebt. Gebruik voor cryptografische hashes een klasse die is afgeleid van de System.Security.Cryptography.HashAlgorithm of System.Security.Cryptography.KeyedHashAlgorithm klasse.
- Test niet op gelijkheid van hash-codes om te bepalen of twee objecten gelijk zijn. (Ongelijke objecten kunnen identieke hashcodes hebben.) Als u wilt testen op gelijkheid, roept u de ReferenceEquals of Equals methode aan.
De GetHashCode methode kan worden overschreven door een afgeleid type. Als GetHashCode niet wordt overschreven, worden hashcodes voor referentietypen berekend door de Object.GetHashCode-methode van de basisklasse aan te roepen, die een hashcode berekent op basis van de verwijzing van een object; voor meer informatie, zie RuntimeHelpers.GetHashCode. Met andere woorden, twee objecten waarvoor de ReferenceEquals methode retourneert true , hebben identieke hashcodes. Als de waarde typen geen GetHashCode overschrijven, gebruikt de ValueType.GetHashCode methode van de basisklasse reflectie om de hash-code te berekenen op basis van de waarden van de velden van het type. Met andere woorden, waardetypen waarvan de velden gelijke waarden hebben, hebben gelijke hashcodes. Zie de sectie Notities voor erfgenamen voor meer informatie over het overschrijven van GetHashCode.
Warning
Als u de GetHashCode methode overschrijft, moet u ook de Equals overschrijven, en omgekeerd. Als uw overschreven Equals methode retourneert true wanneer twee objecten worden getest op gelijkheid, moet de overschreven GetHashCode methode dezelfde waarde retourneren voor de twee objecten.
Als een object dat wordt gebruikt als sleutel in een hash-tabel geen nuttige implementatie van GetHashCode biedt, kunt u een hashcodeprovider opgeven door een IEqualityComparer implementatie te leveren aan een van de overbelastingen van de constructeur van de Hashtable klasse.
Notities voor overnemers
Een hash-functie wordt gebruikt om snel een getal (hashcode) te genereren dat overeenkomt met de waarde van een object. Hash-functies zijn meestal specifiek voor elk type en moeten voor uniekheid ten minste één van de exemplaarvelden als invoer gebruiken. Hash-codes mogen niet worden berekend met behulp van de waarden van statische velden.
Voor klassen die zijn afgeleid van Object, kan de GetHashCode methode alleen delegeren aan de basisklasse-implementatie GetHashCode() als de afgeleide klasse gelijkheid definieert om te verwijzen naar gelijkheid. De standaard implementatie van GetHashCode() referentietypen retourneert een hash-code die gelijk is aan de code die door de GetHashCode(Object) methode wordt geretourneerd. U kunt overschrijven GetHashCode() voor onveranderbare verwijzingstypen. Over het algemeen moet u voor onveranderbare verwijzingstypen alleen overschrijven GetHashCode() als:
U kunt de hashcode berekenen op basis van velden die niet kunnen worden gedempt; Of
U kunt ervoor zorgen dat de hashcode van een veranderlijk object niet verandert terwijl het object zich in een verzameling bevindt die afhankelijk is van de hashcode.
Anders denkt u dat het veranderlijke object verloren gaat in de hash-tabel. Als u ervoor kiest om te overschrijven GetHashCode() voor een onveranderbaar verwijzingstype, moet uw documentatie duidelijk maken dat gebruikers van uw type geen objectwaarden mogen wijzigen terwijl het object is opgeslagen in een hash-tabel.
Voor waardetypen GetHashCode() biedt u een standaard-hashcode-implementatie die gebruikmaakt van weerspiegeling. Overweeg deze te overschrijven voor betere prestaties.
Zie de sectie Voorbeelden voor meer informatie en voorbeelden die hashcodes op verschillende manieren berekenen.
Een hash-functie moet de volgende eigenschappen hebben:
Als twee objecten gelijk zijn aan elkaar vergelijken, moet de GetHashCode() methode voor elk object dezelfde waarde retourneren. Als twee objecten echter niet als gelijk worden vergeleken, hoeven de GetHashCode() methoden voor de twee objecten geen verschillende waarden te retourneren.
De GetHashCode() methode voor een object moet consistent dezelfde hash-code retourneren zolang er geen wijziging is in de objectstatus waarmee de retourwaarde van de methode System.Object.Equals van het object wordt bepaald. Houd er rekening mee dat dit alleen geldt voor de huidige uitvoering van een toepassing en dat een andere hash-code kan worden geretourneerd als de toepassing opnieuw wordt uitgevoerd.
Voor de beste prestaties moet een hash-functie een gelijkmatige distributie genereren voor alle invoer, inclusief invoer die sterk is geclusterd. Een implicatie is dat kleine wijzigingen in de objectstatus leiden tot grote wijzigingen in de resulterende hash-code voor de beste hashtabelprestaties.
Hash-functies moeten goedkoop zijn om te berekenen.
De GetHashCode() methode mag geen uitzonderingen genereren.
De implementatie van de GetHashCode() methode die door de String klasse wordt geleverd, retourneert bijvoorbeeld identieke hashcodes voor identieke tekenreekswaarden. Daarom retourneren twee String objecten dezelfde hashcode als ze dezelfde tekenreekswaarde vertegenwoordigen. De methode gebruikt ook alle tekens in de tekenreeks om redelijk willekeurig gedistribueerde uitvoer te genereren, zelfs wanneer de invoer is geclusterd in bepaalde bereiken (veel gebruikers kunnen bijvoorbeeld tekenreeksen hebben die alleen de lagere 128 ASCII-tekens bevatten, zelfs als een tekenreeks een van de 65.535 Unicode-tekens kan bevatten).
Het leveren van een goede hash-functie voor een klasse kan aanzienlijk van invloed zijn op de prestaties van het toevoegen van deze objecten aan een hash-tabel. In een hashtabel met sleutels die een goede implementatie van een hash-functie bieden, kost het zoeken naar een element constante tijd (bijvoorbeeld een O(1)-bewerking. In een hash-tabel met een slechte implementatie van een hash-functie is de prestaties van een zoekopdracht afhankelijk van het aantal items in de hash-tabel (bijvoorbeeld een O(n-bewerking, waarbij n het aantal items in de hash-tabel is). Een kwaadwillende gebruiker kan gegevens invoeren die het aantal botsingen verhogen, waardoor de prestaties van toepassingen die afhankelijk zijn van hashtabellen aanzienlijk kunnen afnemen, onder de volgende omstandigheden:
Wanneer hashfuncties frequente botsingen produceren.
Wanneer een groot deel van objecten in een hash-tabel hashcodes produceert die gelijk zijn aan of ongeveer gelijk zijn aan elkaar.
Wanneer gebruikers de gegevens invoeren waaruit de hashcode wordt berekend.
Afgeleide klassen die moeten GetHashCode() worden overschreven, moeten ook worden overschreven Equals(Object) om te garanderen dat twee objecten die als gelijk worden beschouwd, dezelfde hash-code hebben; anders werkt het Hashtable type mogelijk niet correct.