0Pricing
C# Academy · Lektion

GetHashCode überschreiben

Sorgen Sie für Konsistenz zwischen Gleichheit und Hashing.

GetHashCode überschreiben ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Warum GetHashCode wichtig ist

Hashbasierte Sammlungen wie Dictionary und HashSet verwenden GetHashCode, um Elemente Buckets zuzuordnen. Wenn Sie Equals, aber nicht GetHashCode überschreiben, können diese Sammlungen gleiche Elemente möglicherweise nicht finden.

Die goldene Regel

Der Vertrag ist einfach: Wenn zwei Objekte gleich sind, müssen sie denselben Hashcode zurückgeben. Umgekehrt ist das nicht erforderlich; verschiedene Objekte dürfen denselben Hashcode haben, also eine Kollision verursachen.

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());
    }
}

HashCode.Combine verwenden

Das Hilfsprogramm HashCode.Combine mischt mehrere Feldwerte zu einem gut verteilten Hash. Es ist die empfohlene moderne Methode zur Implementierung von 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());
    }
}

Gleichheit und Hashing gemeinsam überschreiben

Überschreiben Sie Equals und GetHashCode immer gemeinsam und verwenden Sie in beiden dieselben Felder. Die Verwendung unterschiedlicher Felder führt dazu, dass gleiche Objekte unterschiedliche Hashcodes erzeugen.

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());
    }
}

Warum Dictionaries es benötigen

Ein Dictionary berechnet zunächst den Hash des Schlüssels, um einen Bucket zu finden, und verwendet anschließend Equals innerhalb dieses Buckets. Ein falscher Hash führt die Suche in den falschen Bucket, sodass der Schlüssel nie gefunden wird.

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)]);
    }
}

Unveränderliche Felder hashen

Hashcodes sollten für ein Objekt stabil bleiben, solange es in einer Hashsammlung lebt. Bauen Sie den Hash auf unveränderlichen Feldern auf. Wenn sich ein Schlüssel nach dem Einfügen ändert, kann die Sammlung ihn nicht mehr finden.

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());
    }
}

Umgang mit null-Feldern

Wenn ein Feld null sein kann, behandelt HashCode.Combine diesen Fall sicher. Wenn Sie den Hash manuell berechnen, müssen Sie null abfangen, um eine NullReferenceException zu vermeiden.

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());
    }
}

Kollisionen sind normal

Hashcodes sind 32 Bit groß, daher sind Kollisionen bei großen Datenmengen unvermeidlich. Ein guter Hash verteilt Werte lediglich so, dass Kollisionen selten bleiben; Equals löst die auftretenden Kollisionen auf.

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));
    }
}

Records erzeugen ihn für Sie

Ein record erzeugt automatisch einen korrekten GetHashCode aus seinen Eigenschaften, passend zu seinem wertbasierten Equals. Das ist der einfachste Weg, korrektes Hashing zu erhalten.

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)));
    }
}

Ein korrekter Equatable-Typ

Alles zusammengefasst: dieselben Felder in Equals und GetHashCode, unveränderliche Schlüssel und HashCode.Combine zum Mischen. Dieser Typ funktioniert fehlerfrei als Schlüssel eines Dictionary.

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)]);
    }
}

Probieren Sie es selbst aus

Belegen Sie, dass der Vertrag eingehalten wird: Erstellen Sie zwei gleiche Schlüssel und bestätigen Sie, dass sowohl ihre Gleichheit als auch ihre Hashcodes übereinstimmen. Verwenden Sie sie anschließend in einer Menge.

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));
    }
}

Kurzer Test

Rufen Sie sich den Hashing-Vertrag ins Gedächtnis.

Zusammenfassung

Korrektes Hashing sorgt dafür, dass hashbasierte Sammlungen funktionieren.

  • Gleiche Objekte müssen denselben Hashcode zurückgeben.
  • Verwenden Sie HashCode.Combine mit denselben Feldern wie in Equals.
  • Hashen Sie unveränderliche Felder, damit Schlüssel auffindbar bleiben.
  • Kollisionen sind normal; Equals löst sie auf.
  • Records erzeugen automatisch eine korrekte Implementierung.

Häufig gestellte Fragen

Ist die Lektion „GetHashCode überschreiben“ kostenlos?

Ja — der vollständige Text von „GetHashCode überschreiben“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „GetHashCode überschreiben“?

Sorgen Sie für Konsistenz zwischen Gleichheit und Hashing. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C# Academy zu starten?

Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „GetHashCode überschreiben“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?

Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. IEquatable implementieren
  2. GetHashCode überschreiben
  3. IComparable implementieren
  4. IComparer für benutzerdefinierte Sortierung
← Zurück zu C# Academy