0Pricing
C# Academy · Lekcja

Równość wartości i dekonstrukcja

Poznaj strukturalną równość rekordów, przesłaniaj Equals/GetHashCode i używaj wzorców dekonstrukcji.

Równość wartości i dekonstrukcja to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Dogłębne omówienie równości rekordów

Rekordy automatycznie generują Equals, GetHashCode oraz operatory ==/!=, które porównują strukturalnie wszystkie właściwości. Zrozumienie tego mechanizmu pomaga poprawnie używać rekordów i w razie potrzeby przesłaniać jego działanie.

Jak działa automatycznie generowana równość

Kompilator generuje kod porównujący każdą właściwość za pomocą EqualityComparer<T>.Default. W przypadku właściwości typów referencyjnych jest to ich własna metoda Equals, a nie równość referencyjna.

public record Address(string Street, string City);
public record Person(string Name, Address HomeAddress);

var a = new Person("Alice", new Address("123 Main", "NYC"));
var b = new Person("Alice", new Address("123 Main", "NYC"));

Console.WriteLine(a == b); // True — deep structural equality
// Equality checks:
// Name: "Alice" == "Alice" ✓
// HomeAddress: compares Address properties recursively ✓

Przesłanianie generowanej równości

W rekordzie można przesłonić Equals i GetHashCode, gdy potrzebna jest niestandardowa logika porównywania — na przykład porównywanie tylko podzbioru właściwości.

public record Customer(int Id, string Name, string Email)
{
    // Consider customers equal if they have the same ID,
    // regardless of name or email changes
    public virtual bool Equals(Customer? other)
        => other is not null && Id == other.Id;

    public override int GetHashCode() => Id.GetHashCode();
}

Rekordy w kolekcjach

Ponieważ rekordy implementują IEquatable<T> z równością strukturalną, prawidłowo działają jako klucze słowników, w HashSetach oraz z metodami LINQ Distinct i GroupBy.

public record Tag(string Name, string Color);

var tags = new List<Tag>
{
    new("C#", "blue"), new("C#", "blue"), new("dotnet", "purple")
};

var unique = tags.Distinct().ToList(); // [Tag(C#, blue), Tag(dotnet, purple)]

var set = new HashSet<Tag>(tags);
set.Contains(new Tag("C#", "blue")); // true

Dekonstrukcja: podstawy

Rekordy pozycyjne automatycznie generują metodę Deconstruct z parametrami out dla każdej właściwości pozycyjnej. Umożliwia to rozpakowywanie podobne do obsługi krotek.

public record Point(double X, double Y);
public record RGB(byte R, byte G, byte B);

var p = new Point(3.0, 4.0);
var (x, y) = p; // deconstruct
Console.WriteLine($"{x}, {y}");

var color = new RGB(255, 128, 0);
var (r, g, b) = color;
Console.WriteLine($"R={r}, G={g}, B={b}");

Dekonstrukcja podczas dopasowywania wzorców

Dekonstrukcja rekordów w wyrażeniach switch umożliwia zaawansowane pozycyjne dopasowywanie wzorców.

public record Point(int X, int Y);

string Classify(Point p) => p switch
{
    (0, 0)           => "Origin",
    (int x, 0)       => $"X-axis at {x}",
    (0, int y)       => $"Y-axis at {y}",
    (int x, int y) when x == y => $"Diagonal at {x}",
    (int x, int y)   => $"Point ({x}, {y})"
};

Console.WriteLine(Classify(new Point(0, 0)));  // Origin
Console.WriteLine(Classify(new Point(3, 3)));  // Diagonal at 3

Niestandardowe metody Deconstruct

Rekordy niepozycyjne (podobnie jak dowolne klasy) mogą ręcznie dodawać metodę Deconstruct. Metody rozszerzające również mogą dodawać dekonstrukcję do istniejących typów.

public class Temperature
{
    public double Celsius { get; }
    public Temperature(double c) => Celsius = c;

    // Manual Deconstruct
    public void Deconstruct(out double celsius, out double fahrenheit)
    {
        celsius    = Celsius;
        fahrenheit = Celsius * 9 / 5 + 32;
    }
}

var t = new Temperature(100);
var (c, f) = t;
Console.WriteLine($"{c}°C = {f}°F"); // 100°C = 212°F

Pomijanie części dekonstrukcji

Należy używać odrzuceń (_), aby ignorować niepotrzebne części dekonstrukcji — podobnie jak w przypadku odrzuceń krotek.

public record Order(int Id, string Customer, decimal Total, DateTime Date);

var order = new Order(42, "Alice", 99.99m, DateTime.UtcNow);

// Only want Id and Total
var (id, _, total, _) = order;
Console.WriteLine($"Order {id}: ${total}");

// In switch: ignore some fields
string Classify(Order o) => o switch
{
    (_, _, > 1000, _) => "High value",
    (_, _, > 100, _)  => "Medium value",
    _                 => "Low value"
};

Wzorce właściwości a wzorce pozycyjne

Rekordy obsługują zarówno wzorce pozycyjne (oparte na pozycji), jak i wzorce właściwości (oparte na nazwie). Wzorce właściwości są czytelniejsze w przypadku rekordów z wieloma właściwościami.

public record Order(int Id, string Status, decimal Total);

// Positional pattern:
string DescribePos(Order o) => o switch
{
    (_, "Shipped", > 100) => "High-value shipped",
    _                     => "Other"
};

// Property pattern (more readable):
string DescribeProp(Order o) => o switch
{
    { Status: "Shipped", Total: > 100 } => "High-value shipped",
    { Status: "Cancelled" }             => "Cancelled",
    _                                   => "Other"
};

Praktyczny przykład: wzorzec typu Result

Typ wyniku w stylu discriminated union, wykorzystujący rekordy i dekonstrukcję — funkcyjne podejście do obsługi błędów.

public abstract record Result<T>;
public record Success<T>(T Value) : Result<T>;
public record Failure<T>(string Error) : Result<T>;

Result<Order> PlaceOrder(CreateOrderRequest req)
{
    if (req.Quantity <= 0)
        return new Failure<Order>("Quantity must be positive");
    var order = CreateOrder(req);
    return new Success<Order>(order);
}

// Consuming:
var result = PlaceOrder(request);
switch (result)
{
    case Success<Order>(var order):
        return Results.Created($"/orders/{order.Id}", order);
    case Failure<Order>(var error):
        return Results.BadRequest(error);
}

Szybkie sprawdzenie

Co powoduje użycie odrzucenia (_) w wyrażeniu dekonstrukcji?

Podsumowanie: Równość wartości i dekonstrukcja

Najważniejsze wnioski:

  • Automatycznie generowane porównanie równości porównuje wszystkie właściwości strukturalnie i rekurencyjnie
  • W rekordach można przesłonić Equals/GetHashCode, aby zastosować niestandardową logikę tożsamości
  • Rekordy poprawnie działają jako elementy HashSet i klucze słowników
  • Rekordy pozycyjne automatycznie generują Deconstruct — należy użyć var (a, b) = record
  • Odrzucenia (_) pozwalają ignorować niepotrzebne wartości pozycyjne podczas dekonstrukcji
  • Wzorce właściwości ({Status: "X"}) są czytelniejsze niż wzorce pozycyjne w przypadku złożonych rekordów

Często zadawane pytania

Czy lekcja „Równość wartości i dekonstrukcja” jest bezpłatna?

Tak — pełny tekst „Równość wartości i dekonstrukcja” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Równość wartości i dekonstrukcja”?

Poznaj strukturalną równość rekordów, przesłaniaj Equals/GetHashCode i używaj wzorców dekonstrukcji. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Równość wartości i dekonstrukcja”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Typy record: podstawy i składnia
  2. Niemutowalność z init i with
  3. Równość wartości i dekonstrukcja
  4. Rekordy w projektowaniu sterowanym domeną
← Powrót do C# Academy