Object.GetHashCode Méthode
Définition
Important
Certaines informations portent sur la préversion du produit qui est susceptible d’être en grande partie modifiée avant sa publication. Microsoft exclut toute garantie, expresse ou implicite, concernant les informations fournies ici.
Sert de fonction de hachage par défaut.
public:
virtual int GetHashCode();
public virtual int GetHashCode();
abstract member GetHashCode : unit -> int
override this.GetHashCode : unit -> int
Public Overridable Function GetHashCode () As Integer
Retours
Code de hachage pour l’objet actuel.
Exemples
L’une des méthodes les plus simples pour calculer un code de hachage pour une valeur numérique qui a la même plage ou une plage plus petite que le Int32 type consiste simplement à retourner cette valeur. L’exemple suivant montre une telle implémentation pour une Number structure.
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
Souvent, un type a plusieurs champs de données qui peuvent participer à la génération du code de hachage. Une façon de générer un code de hachage consiste à combiner ces champs à l’aide d’une XOR (eXclusive OR) opération, comme illustré dans l’exemple suivant.
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
L’exemple précédent retourne le même code de hachage pour (n1, n2) et (n2, n1), et peut donc générer plus de collisions que ce qui est souhaitable. Sur .NET 5+, la solution recommandée consiste à utiliser HashCode.Combine. Il évite le problème de symétrie et produit un code de hachage bien distribué sans surcharge de création d’un Tuple objet.
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
Remarques
La GetHashCode méthode fournit un code de hachage pour les algorithmes qui ont besoin de vérifications rapides de l’égalité des objets. Un code de hachage est une valeur numérique utilisée pour insérer et identifier un objet dans une collection basée sur un hachage, telle que la Dictionary<TKey,TValue> classe, la Hashtable classe ou un type dérivé de la DictionaryBase classe.
Note
Pour plus d’informations sur l’utilisation des codes de hachage dans les tables de hachage et pour certains algorithmes de code de hachage supplémentaires, consultez l’entrée de fonction de hachage dans Wikipédia.
Deux objets égaux renvoient des codes de hachage égaux. Toutefois, l’inverse n’est pas vrai : les codes de hachage égaux n’impliquent pas l’égalité des objets, car différents objets (inégaux) peuvent avoir des codes de hachage identiques. En outre, .NET ne garantit pas l’implémentation par défaut de la méthode GetHashCode, et la valeur retournée par cette méthode peut différer entre les implémentations et plateformes .NET, telles que les plateformes 32 bits et 64 bits. Pour ces raisons, n’utilisez pas l’implémentation par défaut de cette méthode comme identificateur d’objet unique à des fins de hachage. Deux conséquences sont les suivantes :
- Vous ne devez pas supposer que les codes de hachage égaux impliquent l’égalité des objets.
- Vous ne devez jamais conserver ou utiliser un code de hachage en dehors du domaine d’application dans lequel il a été créé, car le même objet peut se hacher entre les domaines d’application, les processus et les plateformes.
Avertissement
Un code de hachage est conçu pour permettre une insertion et une recherche efficaces dans les collections basées sur une table de hachage. Un code de hachage n’est pas une valeur permanente. Pour cette raison :
- Ne sérialisez pas les valeurs de code de hachage ou stockez-les dans des bases de données.
- N’utilisez pas le code de hachage comme clé pour récupérer un objet à partir d’une collection à clés.
- N’envoyez pas de codes de hachage entre les domaines d’application ou les processus. Dans certains cas, les codes de hachage peuvent être calculés par processus ou par domaine d’application.
- N’utilisez pas le code de hachage au lieu d’une valeur retournée par une fonction de hachage cryptographique si vous avez besoin d’un hachage cryptographique solide. Pour les fonctions de hachage cryptographiques, utilisez une classe dérivée de la classe System.Security.Cryptography.HashAlgorithm ou de la classe System.Security.Cryptography.KeyedHashAlgorithm.
- Ne testez pas l’égalité des codes de hachage pour déterminer si deux objets sont égaux. (Les objets inégaux peuvent avoir des codes de hachage identiques.) Pour tester l'égalité, appelez la méthode ReferenceEquals ou Equals.
La GetHashCode méthode peut être substituée par un type dérivé. Si GetHashCode n’est pas remplacé, les codes de hachage pour les types de référence sont calculés en appelant la méthode Object.GetHashCode de la classe de base, qui calcule un code de hachage basé sur la référence d’un objet ; pour en savoir plus, consultez RuntimeHelpers.GetHashCode. En d’autres termes, deux objets pour lesquels la ReferenceEquals méthode retourne true ont des codes de hachage identiques. Si les types valeur ne remplacent GetHashCodepas, la ValueType.GetHashCode méthode de la classe de base utilise la réflexion pour calculer le code de hachage en fonction des valeurs des champs du type. En d’autres termes, les types valeur dont les champs ont des valeurs égales ont des codes de hachage égaux. Pour plus d’informations sur l’annulation de GetHashCode, consultez la section « Notes aux héritiers ».
Avertissement
Si vous remplacez la GetHashCode méthode, vous devez également remplacer Equals, et vice versa. Si votre méthode substituée Equals retourne true lorsque deux objets sont testés pour l’égalité, votre méthode substituée GetHashCode doit retourner la même valeur pour les deux objets.
Si un objet utilisé comme clé dans une table de hachage ne fournit pas une implémentation utile de GetHashCode, vous pouvez spécifier un fournisseur de code de hachage en fournissant une implémentation IEqualityComparer à l'un des surcharges du constructeur de la classe Hashtable.
Notes pour les héritiers
Une fonction de hachage est utilisée pour générer rapidement un nombre (code de hachage) qui correspond à la valeur d’un objet. Les fonctions de hachage sont généralement spécifiques à chaque type et, pour unicité, doivent utiliser au moins un des champs d’instance comme entrée. Les codes de hachage ne doivent pas être calculés à l’aide des valeurs des champs statiques.
Pour les classes dérivées de Object, la GetHashCode méthode peut déléguer à l’implémentation de classe GetHashCode() de base uniquement si la classe dérivée définit l’égalité pour être l’égalité de référence. L’implémentation par défaut des types référence GetHashCode() retourne un code de hachage équivalent à celui retourné par la GetHashCode(Object) méthode. Vous pouvez remplacer GetHashCode() les types de référence immuables. En général, pour les types de référence mutables, vous devez remplacer GetHashCode() uniquement si :
Vous pouvez calculer le code de hachage à partir de champs qui ne sont pas mutables ; Ou
Vous pouvez vous assurer que le code de hachage d’un objet mutable ne change pas pendant que l’objet est contenu dans une collection qui s’appuie sur son code de hachage.
Sinon, vous pouvez penser que l’objet mutable est perdu dans la table de hachage. Si vous choisissez de remplacer GetHashCode() un type de référence mutable, votre documentation doit indiquer clairement que les utilisateurs de votre type ne doivent pas modifier les valeurs d’objet pendant que l’objet est stocké dans une table de hachage.
Pour les types valeur, GetHashCode() fournit une implémentation de code de hachage par défaut qui utilise la réflexion. Vous devez envisager de la remplacer pour de meilleures performances.
Pour plus d’informations et d’exemples qui calculent les codes de hachage de différentes façons, consultez la section Exemples.
Une fonction de hachage doit avoir les propriétés suivantes :
Si deux objets se comparent comme égaux, la GetHashCode() méthode de chaque objet doit retourner la même valeur. Toutefois, si deux objets ne sont pas comparés comme égaux, les GetHashCode() méthodes des deux objets n’ont pas besoin de retourner des valeurs différentes.
La GetHashCode() méthode d’un objet doit retourner constamment le même code de hachage tant qu’il n’existe aucune modification de l’état de l’objet qui détermine la valeur de retour de la méthode System.Object.Equals de l’objet. Notez que cela est vrai uniquement pour l’exécution actuelle d’une application et qu’un code de hachage différent peut être retourné si l’application est réexécuter.
Pour des performances optimales, une fonction de hachage doit générer une distribution uniforme pour toutes les entrées, y compris l’entrée fortement cluster. Une implication est que les petites modifications apportées à l’état de l’objet doivent entraîner de grandes modifications apportées au code de hachage résultant pour optimiser les performances de table de hachage.
Les fonctions de hachage doivent être peu coûteuses à calculer.
La GetHashCode() méthode ne doit pas lever d’exceptions.
Par exemple, l’implémentation de la GetHashCode() méthode fournie par la String classe retourne des codes de hachage identiques pour les valeurs de chaîne identiques. Par conséquent, deux String objets retournent le même code de hachage s’ils représentent la même valeur de chaîne. En outre, la méthode utilise tous les caractères de la chaîne pour générer une sortie distribuée raisonnablement aléatoirement, même lorsque l’entrée est en cluster dans certaines plages (par exemple, de nombreux utilisateurs peuvent avoir des chaînes qui contiennent uniquement les 128 caractères ASCII inférieurs, même si une chaîne peut contenir l’un des 65 535 caractères Unicode).
Fournir une bonne fonction de hachage sur une classe peut affecter considérablement les performances d’ajout de ces objets à une table de hachage. Dans une table de hachage avec des clés qui fournissent une bonne implémentation d’une fonction de hachage, la recherche d’un élément prend du temps constant (par exemple, une opération O(1). Dans une table de hachage avec une implémentation médiocre d’une fonction de hachage, les performances d’une recherche dépendent du nombre d’éléments dans la table de hachage (par exemple, une opération O(n), où n est le nombre d’éléments dans la table de hachage). Un utilisateur malveillant peut entrer des données qui augmentent le nombre de collisions, ce qui peut dégrader considérablement les performances des applications qui dépendent des tables de hachage, dans les conditions suivantes :
Lorsque les fonctions de hachage produisent des collisions fréquentes.
Lorsqu’une grande proportion d’objets d’une table de hachage produit des codes de hachage qui sont égaux ou environ égaux les uns aux autres.
Lorsque les utilisateurs entrent les données à partir desquelles le code de hachage est calculé.
Les classes dérivées qui remplacent GetHashCode() doivent également être remplacées Equals(Object) pour garantir que deux objets considérés comme égaux ont le même code de hachage ; sinon, le Hashtable type peut ne pas fonctionner correctement.