Object.GetHashCode Metod
Definition
Viktigt
En del information gäller för förhandsversionen av en produkt och kan komma att ändras avsevärt innan produkten blir allmänt tillgänglig. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, avseende informationen som visas här.
Fungerar som standard-hash-funktion.
public:
virtual int GetHashCode();
public virtual int GetHashCode();
abstract member GetHashCode : unit -> int
override this.GetHashCode : unit -> int
Public Overridable Function GetHashCode () As Integer
Returer
En hash-kod för det aktuella objektet.
Exempel
Ett av de enklaste sätten Int32 att beräkna en hashkod för ett numeriskt värde som har samma eller ett mindre intervall än typen är att helt enkelt returnera det värdet. I följande exempel visas en sådan implementering för en 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
Ofta har en typ flera datafält som kan delta i genereringen av hash-koden. Ett sätt att generera en hashkod är att kombinera dessa fält med hjälp av en XOR (eXclusive OR) åtgärd, som du ser i följande exempel.
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
I föregående exempel returneras samma hashkod för (n1, n2) och (n2, n1), så det kan generera fler kollisioner än vad som är önskvärt. På .NET 5+ är den rekommenderade lösningen att använda HashCode.Combine. Det undviker symmetriproblemet och skapar en välfördelad hashkod utan att behöva skapa objektet Tuple.
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
Kommentarer
Metoden GetHashCode tillhandahåller en hash-kod för algoritmer som behöver snabbkontroller av objektjämlikhet. En hash-kod är ett numeriskt värde som används för att infoga och identifiera ett objekt i en hash-baserad samling, till exempel Dictionary<TKey,TValue> klassen, Hashtable klassen eller en typ som härletts från DictionaryBase klassen.
Note
Information om hur hashkoder används i hash-tabeller och för ytterligare hashkodalgoritmer finns i hash-funktionsposten i Wikipedia.
Två objekt som är lika returnerar hashkoder som också är lika. Det omvända är dock inte sant: lika hashkoder innebär inte objektjämlikhet, eftersom olika (ojämlika) objekt kan ha identiska hash-koder. Dessutom garanterar .NET inte standardimplementeringen av metoden GetHashCode, och värdet som den här metoden returnerar kan skilja sig mellan .NET implementeringar och plattformar, till exempel mellan 32-bitars- och 64-bitarsplattformar. Av dessa skäl ska du inte använda standardimplementeringen av den här metoden som ett unikt objektidentifierare för hashningsändamål. Två konsekvenser följer av detta:
- Du bör inte anta att lika hashkoder innebär objektjämlikhet.
- Du bör aldrig bevara eller använda en hash-kod utanför programdomänen där den skapades, eftersom samma objekt kan hasha mellan programdomäner, processer och plattformar.
Varning
En hash-kod är avsedd för effektiv infogning och sökning i samlingar som baseras på en hash-tabell. En hash-kod är inte ett permanent värde. Av den anledningen:
- Serialisera inte hash-kodvärden eller lagra dem i databaser.
- Använd inte hash-koden som nyckel för att hämta ett objekt från en nyckelsamling.
- Skicka inte hash-koder mellan programdomäner eller processer. I vissa fall kan hashkoder beräknas per process eller per programdomän.
- Använd inte hashkoden i stället för ett värde som returneras av en kryptografisk hashfunktion om du behöver en kryptografiskt stark hash. För kryptografiska hashar använder du en klass som härletts från System.Security.Cryptography.HashAlgorithm klassen eller System.Security.Cryptography.KeyedHashAlgorithm .
- Testa inte för likhet mellan hashkoder för att avgöra om två objekt är lika. (Ojämlika objekt kan ha identiska hash-koder.) För att testa jämlikhet, anropa metoden ReferenceEquals eller Equals.
Metoden GetHashCode kan åsidosättas av en härledd typ. Om GetHashCode inte åsidosätts beräknas hash-koder för referenstyper genom att anropa Object.GetHashCode metoden för basklassen, som beräknar en hash-kod baserat på ett objekts referens. Mer information RuntimeHelpers.GetHashCodefinns i . Med andra ord har två objekt som ReferenceEquals metoden returnerar true identiska hash-koder för. Om värdetyper inte åsidosätter GetHashCodeValueType.GetHashCode använder metoden för basklassen reflektion för att beräkna hash-koden baserat på värdena för typens fält. Med andra ord har värdetyper vars fält har lika värden lika med hashkoder. Mer information om åsidosättande av GetHashCode finns i avsnittet "Anteckningar till arvtagare".
Varning
Om du åsidosätter GetHashCode metoden bör du också åsidosätta Equals, och vice versa. Om den åsidosatta Equals metoden returnerar true när två objekt testas för likhet måste den åsidosatta GetHashCode metoden returnera samma värde för de två objekten.
Om ett objekt som används som en nyckel i en hash-tabell inte ger någon användbar implementering av GetHashCodekan du ange en hash-kodprovider genom att ange en IEqualityComparer implementering till en av överlagringarna av Hashtable klasskonstruktorn.
Anteckningar till arvingar
En hash-funktion används för att snabbt generera ett tal (hashkod) som motsvarar värdet för ett objekt. Hash-funktioner är vanligtvis specifika för varje typ och måste för unikhet använda minst ett av instansfälten som indata. Hash-koder bör inte beräknas med hjälp av värdena för statiska fält.
För klasser som härleds från ObjectGetHashCode kan metoden endast delegera till basklassimplementeringen GetHashCode() om den härledda klassen definierar likhet som referensjämlikhet. Standardimplementeringen av GetHashCode() för referenstyper returnerar en hash-kod som motsvarar den som returneras av GetHashCode(Object) metoden. Du kan åsidosätta GetHashCode() för oföränderliga referenstyper. För föränderliga referenstyper bör du i allmänhet endast åsidosätta GetHashCode() om:
Du kan beräkna hash-koden från fält som inte kan ändras. Eller
Du kan se till att hash-koden för ett föränderligt objekt inte ändras medan objektet finns i en samling som förlitar sig på dess hash-kod.
Annars kanske du tror att det föränderliga objektet går förlorat i hash-tabellen. Om du väljer att åsidosätta GetHashCode() för en föränderlig referenstyp bör dokumentationen klargöra att användare av din typ inte ska ändra objektvärden medan objektet lagras i en hash-tabell.
För värdetyper GetHashCode() tillhandahåller en standardimplementering av hash-kod som använder reflektion. Du bör överväga att åsidosätta det för bättre prestanda.
Mer information och exempel som beräknar hashkoder på flera olika sätt finns i avsnittet Exempel.
En hash-funktion måste ha följande egenskaper:
Om två objekt jämförs som lika GetHashCode() måste metoden för varje objekt returnera samma värde. Men om två objekt inte jämförs som lika behöver metoderna för de två objekten GetHashCode() inte returnera olika värden.
Metoden GetHashCode() för ett objekt måste konsekvent returnera samma hash-kod så länge det inte finns någon ändring i objekttillståndet som avgör returvärdet för objektets System.Object.Equals-metod . Observera att detta endast gäller för den aktuella körningen av ett program och att en annan hashkod kan returneras om programmet körs igen.
För bästa prestanda bör en hash-funktion generera en jämn distribution för alla indata, inklusive indata som är kraftigt klustrade. En implikation är att små ändringar i objekttillståndet bör resultera i stora ändringar i den resulterande hashkoden för bästa hash-tabellprestanda.
Hash-funktioner bör vara billiga att beräkna.
Metoden GetHashCode() bör inte utlösa undantag.
Implementeringen av metoden GetHashCode() som tillhandahålls av String klassen returnerar till exempel identiska hash-koder för identiska strängvärden. Därför returnerar två String objekt samma hash-kod om de representerar samma strängvärde. Metoden använder också alla tecken i strängen för att generera rimligt slumpmässigt distribuerade utdata, även när indata grupperas i vissa intervall (till exempel kan många användare ha strängar som bara innehåller de lägre 128 ASCII-tecknen, även om en sträng kan innehålla något av de 65 535 Unicode-tecknen).
Att tillhandahålla en bra hash-funktion i en klass kan avsevärt påverka prestanda för att lägga till dessa objekt i en hash-tabell. I en hash-tabell med nycklar som ger en bra implementering av en hash-funktion tar det konstant tid att söka efter ett element (till exempel en O(1)-åtgärd). I en hash-tabell med en dålig implementering av en hash-funktion beror prestanda för en sökning på antalet objekt i hash-tabellen (till exempel en O(n)-åtgärd, där n är antalet objekt i hash-tabellen). En obehörig användare kan mata in data som ökar antalet kollisioner, vilket avsevärt kan försämra prestandan för program som är beroende av hash-tabeller under följande förhållanden:
När hash-funktioner ger upphov till frekventa kollisioner.
När en stor del av objekten i en hashtabell skapar hash-koder som är lika med eller ungefär lika med varandra.
När användarna anger de data som hashkoden beräknas från.
Härledda klasser som åsidosätter GetHashCode() måste också åsidosättas Equals(Object) för att garantera att två objekt som anses vara lika har samma hash-kod. Annars Hashtable kanske typen inte fungerar korrekt.