C# Academy · Lektion

Värdelikhet och dekomponering

Förstå strukturell likhet hos records, åsidosätt Equals/GetHashCode och använd dekomponeringsmönster.

Lektion 3 av 412 steg

Värdelikhet och dekomponering är en gratis lektion i C# Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för C# Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i C# Academy innehåller totalt 4 lektioner.

Fördjupning: Record-likhet

Records genererar automatiskt Equals, GetHashCode och operatorerna ==/!=, som jämför alla egenskaper strukturellt. Om du förstår hur detta fungerar blir det lättare att använda records korrekt och att åsidosätta beteendet när det behövs.

Så fungerar automatiskt genererad likhet

Kompilatorn genererar kod som jämför varje egenskap med EqualityComparer<T>.Default. För egenskaper av referenstyp används deras egen Equals – inte referenslikhet.

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 ✓

Åsidosätta genererad likhet

Du kan åsidosätta Equals och GetHashCode på en record när du vill ha anpassad likhetslogik – till exempel genom att bara jämföra en delmängd av egenskaperna.

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

Records i samlingar

Eftersom records implementerar IEquatable<T> med strukturell likhet fungerar de korrekt som nycklar i dictionaries, i HashSets och med LINQ:s Distinct och 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

Destrukturering: grunderna

Positionella records genererar automatiskt en Deconstruct-metod med out-parametrar för varje positionell egenskap. Det möjliggör uppackning som liknar tupler.

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

Destrukturering i mönstermatchning

När records destruktureras i switch-uttryck möjliggör det kraftfull mönstermatchning efter position.

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

Anpassade Deconstruct-metoder

Icke-positionella records (och alla klasser) kan lägga till en Deconstruct-metod manuellt. Tilläggsmetoder kan också lägga till destrukturering i befintliga typer.

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

Ignorera delar av destruktureringen

Använd discard-värden (_) för att ignorera oönskade delar av en destrukturering – ungefär som discard-värden för tupler.

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

Egenskapsmönster jämfört med positionella mönster

Records stöder både positionella mönster (efter position) och egenskapsmönster (efter namn). Egenskapsmönster är lättare att läsa för records med många egenskaper.

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

Verklighetsnära: Resultattypsmönster

En resultattyp i stil med en discriminated union som använder records och destrukturering – ett funktionellt sätt att hantera fel.

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

Snabbkontroll

Vad gör det att använda ett discard-värde (_) i ett destruktureringsuttryck?

Sammanfattning: Värdebaserad likhet och destrukturering

Viktiga slutsatser:

  • Automatiskt genererad likhet jämför alla egenskaper strukturellt och rekursivt
  • Åsidosätt Equals/GetHashCode i records för anpassad identitetslogik
  • Records fungerar korrekt som element i HashSet och som nycklar i dictionary
  • Positionsbaserade records genererar automatiskt Deconstruct — använd var (a, b) = record
  • Discards (_) ignorerar oönskade positionsvärden vid dekonstruering
  • Egenskapsmönster ({Status: "X"}) är mer lättlästa än positionsmönster för komplexa records
Gratis att börja

Lär dig C# med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
93
Lektioner
346

Vanliga frågor

Är lektionen ”Värdelikhet och dekomponering” gratis?

Ja – hela texten till ”Värdelikhet och dekomponering” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i C# Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i C# Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Värdelikhet och dekomponering”?

Förstå strukturell likhet hos records, åsidosätt Equals/GetHashCode och använd dekomponeringsmönster. Ni övar på C# Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig C# Academy?

Du behöver inga förkunskaper. Utbildningen i C# Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Värdelikhet och dekomponering”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här C# Academy-lektionen?

Ja. Varje C# Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Record-typer: grunder och syntax
  2. Oföränderlighet med init och with
  3. Värdelikhet och dekomponering
  4. Records i domändriven design
← Tillbaka till C# Academy