GetHashCode overschrijven
Zorg dat gelijkheid en hashing consistent zijn.
GetHashCode overschrijven is een gratis C# Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject C# Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus C# Academy bevat in totaal 4 lessen.
Waarom GetHashCode belangrijk is
Hashgebaseerde collecties zoals Dictionary en HashSet gebruiken GetHashCode om items over buckets te verdelen. Als je Equals wel overschrijft maar GetHashCode niet, kunnen deze collecties gelijke items niet terugvinden.
De gouden regel
Het contract is eenvoudig: als twee objecten gelijk zijn, moeten ze dezelfde hashcode teruggeven. Het omgekeerde is niet vereist; verschillende objecten mogen dezelfde hashcode hebben (een botsing).
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());
}
}Gebruik HashCode.Combine
De hulpfunctie HashCode.Combine combineert verschillende veldwaarden tot een goed verdeelde hash. Dit is de aanbevolen moderne manier om GetHashCode te implementeren.
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());
}
}Gelijkheid en hashing samen als basis
Overschrijf Equals en GetHashCode altijd als paar en gebruik in beide dezelfde velden. Als je verschillende velden gebruikt, produceren gelijke objecten verschillende hashes.
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());
}
}Waarom dictionaries dit nodig hebben
Een Dictionary berekent eerst de hash van de sleutel om een bucket te vinden en gebruikt daarna Equals binnen die bucket. Een onjuiste hash stuurt een zoekactie naar de verkeerde bucket, waardoor de sleutel nooit wordt gevonden.
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)]);
}
}Onveranderlijke velden hashen
Hashcodes moeten stabiel blijven voor een object zolang het in een hashcollectie leeft. Baseer de hash op onveranderlijke velden; als een sleutel na invoeging verandert, kan de collectie het spoor ervan kwijtraken.
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());
}
}Omgaan met null-velden
Wanneer een veld null kan zijn, handelt HashCode.Combine dit veilig af. Als je de hash handmatig berekent, moet je null afvangen om een NullReferenceException te voorkomen.
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());
}
}Botsingen zijn normaal
Hashcodes zijn 32-bits, dus botsingen zijn onvermijdelijk bij grote gegevensverzamelingen. Een goede hash verspreidt waarden alleen zo dat botsingen zeldzaam blijven; Equals handelt eventuele botsingen af.
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));
}
}Recordtypen genereren dit voor je
Een record genereert automatisch een correcte GetHashCode op basis van zijn eigenschappen, in overeenstemming met zijn waardegebaseerde Equals. Dit is de eenvoudigste manier om hashing goed te implementeren.
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)));
}
}Een correct equatable type
Alles samengebracht: dezelfde velden in Equals en GetHashCode, onveranderlijke sleutels en HashCode.Combine om de waarden te combineren. Dit type werkt probleemloos als sleutel in een 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)]);
}
}Probeer het zelf
Toon aan dat het contract geldt: maak twee gelijke sleutels en controleer of zowel hun gelijkheid als hun hashcodes overeenkomen. Gebruik ze daarna in een 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));
}
}Korte controle
Haal het hashcontract terug.
Samenvatting
Correcte hashing zorgt ervoor dat hashgebaseerde collecties blijven werken.
- Gelijke objecten moeten dezelfde hashcode teruggeven.
- Gebruik
HashCode.Combinevoor dezelfde velden als inEquals. - Hash onveranderlijke velden, zodat sleutels vindbaar blijven.
- Botsingen zijn normaal;
Equalshandelt ze af. - Recordtypen genereren automatisch een correcte implementatie.
Leer C# met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 93
- Lessen
- 346
Veelgestelde vragen
Is de les “GetHashCode overschrijven” gratis?
Ja — de volledige tekst van “GetHashCode overschrijven” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus C# Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus C# Academy bevat in totaal 4 lessen.
Wat leer ik in “GetHashCode overschrijven”?
Zorg dat gelijkheid en hashing consistent zijn. Je oefent met C# Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met C# Academy te beginnen?
Ervaring vooraf is niet nodig. C# Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “GetHashCode overschrijven”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over C# Academy?
Ja. Elke les over C# Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- IEquatable implementeren
- GetHashCode overschrijven
- IComparable implementeren
- IComparer voor aangepast sorteren