0Pricing
C# Academy · Leçon

Remplacer GetHashCode

Gardez l’égalité et le hachage cohérents.

Remplacer GetHashCode est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Pourquoi GetHashCode est important

Les collections fondées sur le hachage, comme Dictionary et HashSet, utilisent GetHashCode pour répartir les éléments dans des compartiments. Si vous redéfinissez Equals mais pas GetHashCode, ces collections peuvent ne pas trouver les éléments égaux.

La règle d'or

Le contrat est simple : si deux objets sont égaux, ils doivent renvoyer le même code de hachage. L'inverse n'est pas requis ; des objets différents peuvent partager un code de hachage, ce qui constitue une collision.

using System;

public struct Point
{
    public int X, Y;
    public Point(int x, int y) { X = x; Y = y; }
    public override bool Equals(object obj) => obj is Point p && p.X == X && p.Y == Y;
    public override int GetHashCode() => HashCode.Combine(X, Y);
}

public class Program
{
    public static void Main()
    {
        var a = new Point(1, 2);
        var b = new Point(1, 2);
        Console.WriteLine(a.Equals(b));
        Console.WriteLine(a.GetHashCode() == b.GetHashCode());
    }
}

Utiliser HashCode.Combine

L'outil HashCode.Combine mélange plusieurs valeurs de champs pour produire un hachage bien réparti. C'est la méthode moderne recommandée pour implémenter GetHashCode.

using System;

public struct Color
{
    public int R, G, B;
    public Color(int r, int g, int b) { R = r; G = g; B = b; }
    public override bool Equals(object obj) => obj is Color c && c.R == R && c.G == G && c.B == B;
    public override int GetHashCode() => HashCode.Combine(R, G, B);
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Color(255, 0, 0).GetHashCode() == new Color(255, 0, 0).GetHashCode());
    }
}

Associer égalité et hachage

Redéfinissez toujours Equals et GetHashCode ensemble, en utilisant les mêmes champs dans les deux méthodes. Utiliser des champs différents fait produire des hachages différents à des objets égaux.

using System;

public class Book
{
    public string Title;
    public int Year;
    public Book(string title, int year) { Title = title; Year = year; }
    public override bool Equals(object obj)
        => obj is Book b && b.Title == Title && b.Year == Year;
    public override int GetHashCode() => HashCode.Combine(Title, Year);
}

public class Program
{
    public static void Main()
    {
        var a = new Book("C#", 2020);
        var b = new Book("C#", 2020);
        Console.WriteLine(a.GetHashCode() == b.GetHashCode());
    }
}

Pourquoi les dictionnaires en ont besoin

Un Dictionary hache d'abord la clé pour trouver un compartiment, puis utilise Equals dans ce compartiment. Un hachage incorrect envoie la recherche dans le mauvais compartiment, et la clé n'est jamais trouvée.

using System;
using System.Collections.Generic;

public struct Coord
{
    public int X, Y;
    public Coord(int x, int y) { X = x; Y = y; }
    public override bool Equals(object obj) => obj is Coord c && c.X == X && c.Y == Y;
    public override int GetHashCode() => HashCode.Combine(X, Y);
}

public class Program
{
    public static void Main()
    {
        var map = new Dictionary<Coord, string> { [new Coord(2, 3)] = "hit" };
        Console.WriteLine(map[new Coord(2, 3)]);
    }
}

Hacher les champs immuables

Les codes de hachage devraient rester stables pour un objet tant que celui-ci se trouve dans une collection fondée sur le hachage. Fondez le hachage sur des champs immuables ; si une clé est modifiée après son insertion, la collection peut perdre sa trace.

using System;

public class Account
{
    public readonly int Id; // immutable, safe to hash
    public string Nickname; // mutable, do not hash
    public Account(int id, string nick) { Id = id; Nickname = nick; }
    public override bool Equals(object obj) => obj is Account a && a.Id == Id;
    public override int GetHashCode() => Id.GetHashCode();
}

public class Program
{
    public static void Main()
    {
        var acc = new Account(42, "old");
        int h1 = acc.GetHashCode();
        acc.Nickname = "new"; // does not change the hash
        Console.WriteLine(h1 == acc.GetHashCode());
    }
}

Gérer les champs nuls

Lorsqu'un champ peut être nul, HashCode.Combine le gère sans risque. Si vous effectuez le calcul manuellement, protégez-vous contre les valeurs nulles pour éviter une NullReferenceException.

using System;

public class Tag
{
    public string Name;
    public Tag(string name) { Name = name; }
    public override bool Equals(object obj) => obj is Tag t && t.Name == Name;
    public override int GetHashCode() => HashCode.Combine(Name); // null-safe
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Tag(null).GetHashCode() == new Tag(null).GetHashCode());
    }
}

Les collisions sont normales

Les codes de hachage sont codés sur 32 bits, les collisions sont donc inévitables pour de grands ensembles de données. Un bon hachage répartit simplement les valeurs afin de rendre les collisions rares ; Equals résout celles qui se produisent.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var set = new HashSet<int>();
        for (int i = 0; i < 5; i++) set.Add(i);
        // Equality still works perfectly even though hashing is imperfect in general
        Console.WriteLine(set.Contains(3));
        Console.WriteLine(set.Contains(99));
    }
}

Les enregistrements le génèrent pour vous

Un record génère automatiquement un GetHashCode correct à partir de ses propriétés, en accord avec sa méthode Equals fondée sur les valeurs. C'est la manière la plus simple d'obtenir un hachage correct.

using System;
using System.Collections.Generic;

public record Coord(int X, int Y);

public class Program
{
    public static void Main()
    {
        var set = new HashSet<Coord> { new Coord(1, 1) };
        Console.WriteLine(set.Contains(new Coord(1, 1)));
    }
}

Un type équatable correct

En résumé : les mêmes champs dans Equals et GetHashCode, des clés immuables et HashCode.Combine pour le mélange. Ce type fonctionne parfaitement comme clé de dictionnaire.

using System;
using System.Collections.Generic;

public struct ProductKey
{
    public string Sku;
    public int Variant;
    public ProductKey(string sku, int variant) { Sku = sku; Variant = variant; }
    public override bool Equals(object obj)
        => obj is ProductKey k && k.Sku == Sku && k.Variant == Variant;
    public override int GetHashCode() => HashCode.Combine(Sku, Variant);
}

public class Program
{
    public static void Main()
    {
        var stock = new Dictionary<ProductKey, int>
        {
            [new ProductKey("ABC", 1)] = 10
        };
        Console.WriteLine(stock[new ProductKey("ABC", 1)]);
    }
}

Essayez vous-même

Vérifiez que le contrat est respecté : construisez deux clés égales et confirmez que leur égalité et leurs codes de hachage correspondent, puis utilisez-les dans un set.

using System;
using System.Collections.Generic;

public struct Name
{
    public string First, Last;
    public Name(string first, string last) { First = first; Last = last; }
    public override bool Equals(object obj) => obj is Name n && n.First == First && n.Last == Last;
    public override int GetHashCode() => HashCode.Combine(First, Last);
}

public class Program
{
    public static void Main()
    {
        var a = new Name("Ada", "Lovelace");
        var b = new Name("Ada", "Lovelace");
        Console.WriteLine(a.Equals(b) + " " + (a.GetHashCode() == b.GetHashCode()));
        var people = new HashSet<Name> { a };
        Console.WriteLine(people.Contains(b));
    }
}

Vérification rapide

Rappelez-vous le contrat du hachage.

Récapitulatif

Un hachage correct permet aux collections fondées sur le hachage de fonctionner correctement.

  • Les objets égaux doivent renvoyer le même code de hachage.
  • Utilisez HashCode.Combine sur les mêmes champs que Equals.
  • Hachez des champs immuables afin que les clés restent trouvables.
  • Les collisions sont normales ; Equals les résout.
  • Les enregistrements génèrent automatiquement une implémentation correcte.

Questions Fréquemment Posées

La leçon « Remplacer GetHashCode » est-elle gratuite ?

Oui — le texte complet de « Remplacer GetHashCode » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Remplacer GetHashCode » ?

Gardez l’égalité et le hachage cohérents. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Remplacer GetHashCode » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Implémenter IEquatable
  2. Remplacer GetHashCode
  3. Implémenter IComparable
  4. IComparer pour un tri personnalisé
← Retour à C# Academy