Tilsidesættelse af GetHashCode
Sørg for overensstemmelse mellem lighed og hashing.
Tilsidesættelse af GetHashCode er en gratis C# Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i C# Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. C# Academy-kurset indeholder 4 lektioner i alt.
Hvorfor GetHashCode er vigtigt
Hashbaserede samlinger som Dictionary og HashSet bruger GetHashCode til at placere elementer i grupper. Hvis du tilsidesætter Equals, men ikke GetHashCode, kan disse samlinger ikke finde elementer, der er ens.
Den grundlæggende regel
Reglen er enkel: Hvis to objekter er ens, skal de returnere den samme hashkode. Det omvendte er ikke et krav; forskellige objekter må gerne have samme hashkode, hvilket kaldes en kollision.
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());
}
}Brug HashCode.Combine
Hjælpemetoden HashCode.Combine kombinerer flere feltværdier til en hash med en god fordeling. Det er den anbefalede moderne måde at implementere GetHashCode på.
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());
}
}Implementér lighed og hashing sammen
Tilsidesæt altid Equals og GetHashCode som et par, og brug de samme felter i begge. Hvis du bruger forskellige felter, får ens objekter forskellige hashkoder.
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());
}
}Hvorfor Dictionary har brug for det
En Dictionary beregner først en hash af nøglen for at finde en gruppe og bruger derefter Equals i gruppen. En forkert hash sender opslaget til den forkerte gruppe, så nøglen aldrig bliver fundet.
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)]);
}
}Hashing af uforanderlige felter
Hashkoder bør være stabile for et objekt, mens det befinder sig i en hashbaseret samling. Basér hashen på uforanderlige felter; hvis en nøgle ændres efter indsættelse, kan samlingen miste overblikket over den.
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());
}
}Håndtering af null-felter
Når et felt kan være null, håndterer HashCode.Combine det sikkert. Hvis du beregner hashen manuelt, skal du kontrollere for null for at undgå en 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());
}
}Kollisioner er normale
Hashkoder er 32-bit, så kollisioner er uundgåelige for store datasæt. En god hash fordeler blot værdierne, så kollisioner er sjældne; Equals håndterer dem, når de opstår.
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 genererer det for dig
En record genererer automatisk en korrekt GetHashCode ud fra sine egenskaber, så den stemmer overens med den værdibaserede Equals. Det er den nemmeste måde at få hashing korrekt på.
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)));
}
}En korrekt equatable-type
Hvis vi samler det hele: Brug de samme felter i Equals og GetHashCode, uforanderlige nøgler og HashCode.Combine til at kombinere værdierne. Denne type fungerer fejlfrit som nøgle i en ordbog.
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)]);
}
}Prøv selv
Bevis, at reglen holder: Opret to ens nøgler, og bekræft, at både deres lighed og deres hashkoder stemmer overens. Brug dem derefter i en mængde.
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));
}
}Hurtigt tjek
Genkald dig reglerne for hashing.
Opsummering
Korrekt hashing sørger for, at hashbaserede samlinger fungerer.
- Ens objekter skal returnere den samme hashkode.
- Brug
HashCode.Combinemed de samme felter som iEquals. - Hash uforanderlige felter, så nøgler fortsat kan findes.
- Kollisioner er normale;
Equalshåndterer dem. - Records genererer automatisk en korrekt implementering.
Lær C# med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 93
- Lektioner
- 346
Ofte stillede spørgsmål
Er lektionen “Tilsidesættelse af GetHashCode” gratis?
Ja — hele teksten til “Tilsidesættelse af GetHashCode” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af C# Academy-kurset, skal du opgradere til CoddyKit PRO. C# Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Tilsidesættelse af GetHashCode”?
Sørg for overensstemmelse mellem lighed og hashing. Du øver dig i C# Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på C# Academy?
Der kræves ingen tidligere erfaring. C# Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Tilsidesættelse af GetHashCode”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne C# Academy-lektion?
Ja. Alle C# Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Implementering af IEquatable
- Tilsidesættelse af GetHashCode
- Implementering af IComparable
- IComparer til brugerdefineret sortering