Object.GetHashCode Méthode

Définition

Fait office 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

Int32

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 plus petite plage que le Int32 type consiste simplement à retourner cette valeur. L’exemple suivant montre une implémentation de ce type 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 Example
{
   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
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 Example
   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 indiqué dans l’exemple suivant.

using System;

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

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

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

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

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

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

      pt = new Point(8, 5);
      Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays the following output:
//       13
//       13
' A type that represents a 2-D point.
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 x Xor 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

L’exemple précédent retourne le même code de hachage pour (N1, N2) et (N2, N1). par conséquent, il peut générer plus de collisions que ce qui est souhaitable. Un certain nombre de solutions sont disponibles afin que les codes de hachage dans ces cas ne soient pas identiques. La première consiste à retourner le code de hachage d’un Tuple objet qui reflète l’ordre de chaque champ. L’exemple suivant montre une implémentation possible qui utilise la Tuple<T1,T2> classe. Notez, cependant, que la surcharge de performances liée à l’instanciation d’un Tuple objet peut avoir un impact significatif sur les performances globales d’une application qui stocke un grand nombre d’objets dans des tables de hachage.

using System;

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

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

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

    public override int GetHashCode()
    {
        return Tuple.Create(x, y).GetHashCode();
    }
}

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

        pt = new Point(8, 5);
        Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays the following output:
//       173
//       269
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 Tuple.Create(x, y).GetHashCode()
    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 the following output:
'       173
'       269

Une deuxième solution consiste à pondérer les codes de hachage individuels en décalant les codes de hachage des champs successifs de deux bits ou plus. De manière optimale, les bits décalés au-delà du bit 31 doivent être encapsulés au lieu d’être ignorés. étant donné que les bits sont ignorés par les opérateurs de décalage vers la gauche en C# et Visual Basic, vous devez créer une méthode shift-and-wrap à gauche comme suit :

public int ShiftAndWrap(int value, int positions)
{
    positions = positions & 0x1F;

    // Save the existing bit pattern, but interpret it as an unsigned integer.
    uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
    // Preserve the bits to be discarded.
    uint wrapped = number >> (32 - positions);
    // Shift and wrap the discarded bits.
    return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);
}
Public Function ShiftAndWrap(value As Integer, positions As Integer) As Integer
   positions = positions And &h1F
   
   ' Save the existing bit pattern, but interpret it as an unsigned integer.
   Dim number As UInteger = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0)
   ' Preserve the bits to be discarded.
   Dim wrapped AS UInteger = number >> (32 - positions)
   ' Shift and wrap the discarded bits.
   Return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) Or wrapped), 0)
End Function

L’exemple suivant utilise ensuite cette méthode Shift-and-Wrap pour calculer le code de hachage de la Point structure utilisée dans les exemples précédents.

using System;

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

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

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

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

    public override int GetHashCode()
    {
        return ShiftAndWrap(x.GetHashCode(), 2) ^ y.GetHashCode();
    }

    private int ShiftAndWrap(int value, int positions)
    {
        positions = positions & 0x1F;

        // Save the existing bit pattern, but interpret it as an unsigned integer.
        uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
        // Preserve the bits to be discarded.
        uint wrapped = number >> (32 - positions);
        // Shift and wrap the discarded bits.
        return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);
    }
}

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

        pt = new Point(8, 5);
        Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays the following output:
//       28
//       37
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 ShiftAndWrap(x.GetHashCode(), 2) XOr y.GetHashCode()
    End Function 
    
    Private Function ShiftAndWrap(value As Integer, positions As Integer) As Integer
        positions = positions And &h1F
      
        ' Save the existing bit pattern, but interpret it as an unsigned integer.
        Dim number As UInteger = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0)
        ' Preserve the bits to be discarded.
        Dim wrapped AS UInteger = number >> (32 - positions)
        ' Shift and wrap the discarded bits.
        Return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) Or wrapped), 0)
    End Function
End Structure 

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 the following output:
'       28
'       37

Remarques

Un code de hachage est une valeur numérique utilisée pour insérer et identifier un objet dans une collection basée sur le hachage, telle que la Dictionary<TKey,TValue> classe, la Hashtable classe ou un type dérivé de la DictionaryBase classe. La GetHashCode méthode fournit ce code de hachage pour les algorithmes qui ont besoin de vérifications rapides de l’égalité des objets.

Notes

Pour plus d’informations sur l’utilisation des codes de hachage dans les tables de hachage et pour obtenir d’autres algorithmes de code de hachage, consultez l’entrée de la fonction de hachage dans Wikipédia.

Deux objets qui sont identiques renvoient des codes de hachage qui sont égaux. Toutefois, l’inverse n’est pas vrai : les codes de hachage égaux n’impliquent pas l’égalité des objets, car différents objets (non égaux) peuvent avoir des codes de hachage identiques. en outre, .net ne garantit pas l’implémentation par défaut de la GetHashCode méthode, et la valeur retournée par cette méthode peut différer entre les implémentations de .net, telles que les différentes versions de .NET Framework et .net Core, et les plateformes, 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 en tant qu’identificateur d’objet unique à des fins de hachage. Les deux conséquences sont les suivantes :

  • Vous ne devez pas supposer que les codes de hachage égaux impliquent l’égalité entre les objets.

  • Vous ne devez jamais rendre persistant ou utiliser un code de hachage en dehors du domaine d’application dans lequel il a été créé, car le même objet peut être haché à travers des domaines d’application, des processus et des plateformes.

Avertissement

Un code de hachage est destiné à une insertion et une recherche efficaces dans des 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 ne les stockez pas dans les bases de données.
  • N’utilisez pas le code de hachage comme clé pour récupérer un objet à partir d’une collection à clé.
  • N’envoyez pas de codes de hachage à travers des domaines d’application ou des 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 de chiffrement si vous avez besoin d’un hachage fort du point de vue du chiffrement. Pour les hachages de chiffrement, utilisez une classe dérivée de la System.Security.Cryptography.HashAlgorithm System.Security.Cryptography.KeyedHashAlgorithm classe ou.
  • 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 ReferenceEquals Equals méthode ou.

La GetHashCode méthode peut être substituée par un type dérivé. Si GetHashCode n’est pas substitué, les codes de hachage pour les types référence sont calculés en appelant la Object.GetHashCode méthode de la classe de base, qui calcule un code de hachage en fonction de la référence d’un objet. pour plus d’informations, 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 se substituent pas GetHashCode , 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 GetHashCode la substitution, consultez la section « Remarques à l’héritage ».

Avertissement

Si vous substituez la GetHashCode méthode, vous devez également substituer Equals , et vice versa. Si votre méthode substituée Equals retourne true lorsque deux objets sont testés pour vérifier leur é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 IEqualityComparer implémentation à l’une des surcharges du constructeur de Hashtable classe.

Notes pour le Windows Runtime

quand vous appelez la GetHashCode méthode sur une classe dans le Windows Runtime, elle fournit le comportement par défaut pour les classes qui ne remplacent pas GetHashCode . cela fait partie de la prise en charge fournie par le .NET Framework pour le Windows Runtime (consultez .NET Framework prise en charge Windows des applications du windows Store et des Windows Runtime). les Classes du Windows Runtime n’héritent pas de Object et n’implémentent actuellement pas GetHashCode . toutefois, ils semblent avoir des ToString Equals(Object) méthodes, et GetHashCode lorsque vous les utilisez dans votre code C# ou Visual Basic, et le .NET Framework fournit le comportement par défaut pour ces méthodes.

Notes

Windows les classes d’exécution écrites en C# ou Visual Basic peuvent substituer la GetHashCode méthode.

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 l’unicité, doivent utiliser au moins l’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 la classe de base GetHashCode() uniquement si la classe dérivée définit l’égalité comme étant l’égalité des références. L’implémentation par défaut de GetHashCode() pour les types référence retourne un code de hachage qui est équivalent à celui retourné par la GetHashCode(Object) méthode. Vous pouvez substituer GetHashCode() pour les types de référence immuables. En général, pour les types référence mutables, vous devez substituer GetHashCode() uniquement si : -Vous pouvez calculer le code de hachage à partir de champs qui ne sont pas mutables ; ni -Vous pouvez vous assurer que le code de hachage d’un objet mutable ne change pas lorsque l’objet est contenu dans une collection qui repose sur son code de hachage.

Dans le cas contraire, vous pourriez penser que l’objet mutable est perdu dans la table de hachage. Si vous choisissez de remplacer GetHashCode() pour un type référence mutable, votre documentation doit indiquer clairement que les utilisateurs de votre type ne doivent pas modifier les valeurs d’objet lorsque 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 obtenir de meilleures performances.

Pour obtenir plus d’informations et des exemples qui calculent des codes de hachage de différentes manières, consultez la section exemples.

Une fonction de hachage doit avoir les propriétés suivantes : -Si deux objets sont considérés comme égaux, la GetHashCode() méthode pour chaque objet doit retourner la même valeur. Toutefois, si deux objets ne sont pas considérés comme égaux, les GetHashCode() méthodes pour les deux objets n’ont pas besoin de retourner des valeurs différentes.

-La GetHashCode() méthode d’un objet doit toujours retourner le même code de hachage tant qu’il n’y a 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écutée.

-Pour des performances optimales, une fonction de hachage doit générer une distribution égale pour toutes les entrées, y compris les entrées fortement cluster. Une implication est que de petites modifications de l’état de l’objet doivent entraîner des modifications importantes du code de hachage résultant pour optimiser les performances de la table de hachage.

-Les fonctions de hachage doivent être peu onéreuses pour le calcul.

-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 mise 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).

La fourniture d’une fonction de hachage correcte sur une classe peut affecter de manière significative les performances de l’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 n opération O (), 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 considérablement dégrader les performances des applications qui dépendent de tables de hachage, dans les conditions suivantes : -Lorsque les fonctions de hachage produisent des collisions fréquentes.

-Lorsqu’une grande proportion d’objets dans une table de hachage génère des codes de hachage qui sont égaux ou approximativement égaux.

-Lorsque les utilisateurs saisissent les données à partir desquelles le code de hachage est calculé.

Les classes dérivées qui substituent GetHashCode() doivent également être substituées Equals(Object) pour garantir que deux objets considérés comme égaux ont le même code de hachage ; sinon, le Hashtable type risque de ne pas fonctionner correctement.

S’applique à

Voir aussi