0Pricing
C# Academy · Lezione

Uguaglianza per valore e destrutturazione

Comprenda l'uguaglianza strutturale dei record, esegua l'override di Equals/GetHashCode e usi i pattern di destrutturazione.

Uguaglianza per valore e destrutturazione è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.

Approfondimento sull'uguaglianza dei record

I record generano automaticamente Equals, GetHashCode e gli operatori ==/!=, che confrontano strutturalmente tutte le proprietà. Comprendere questo funzionamento aiuta a utilizzare correttamente i record e a eseguire l'override quando necessario.

Funzionamento dell'uguaglianza generata automaticamente

Il compilatore genera codice che confronta ogni proprietà utilizzando EqualityComparer<T>.Default. Per le proprietà di tipo riferimento, viene usato il relativo Equals, non l'uguaglianza per riferimento.

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 ✓

Override dell'uguaglianza generata

È possibile eseguire l'override di Equals e GetHashCode in un record quando si desidera una logica di uguaglianza personalizzata, ad esempio confrontando solo un sottoinsieme di proprietà.

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

Record nelle raccolte

Poiché i record implementano IEquatable<T> con uguaglianza strutturale, funzionano correttamente come chiavi di dizionario, negli HashSet e con Distinct e GroupBy di LINQ.

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

Destrutturazione: nozioni di base

I record posizionali generano automaticamente un metodo Deconstruct con parametri out per ogni proprietà posizionale. Questo abilita una scomposizione simile a quella delle tuple.

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

Destrutturazione nel pattern matching

La destrutturazione dei record nelle espressioni switch abilita un potente pattern matching posizionale.

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

Metodi Deconstruct personalizzati

I record non posizionali (e qualsiasi classe) possono aggiungere manualmente un metodo Deconstruct. I metodi di estensione possono inoltre aggiungere la destrutturazione ai tipi esistenti.

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

Ignorare parti della destrutturazione

Utilizzare i discard (_) per ignorare le parti indesiderate di una destrutturazione, in modo simile ai discard delle tuple.

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

Pattern di proprietà e pattern posizionali

I record supportano sia i pattern posizionali (basati sulla posizione) sia i pattern di proprietà (basati sul nome). I pattern di proprietà sono più leggibili per i record con molte proprietà.

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

Caso reale: pattern del tipo Result

Un tipo risultato in stile unione discriminata che utilizza record e destrutturazione: un approccio funzionale alla gestione degli errori.

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

Verifica rapida

Che cosa comporta l'uso di un discard (_) in un'espressione di destrutturazione?

Riepilogo: uguaglianza per valore e destrutturazione

Punti chiave:

  • L'uguaglianza generata automaticamente confronta tutte le proprietà in modo strutturale e ricorsivo
  • Eseguire l'override di Equals/GetHashCode nei record per una logica di identità personalizzata
  • I record funzionano correttamente come elementi di HashSet e chiavi di dizionario
  • I record posizionali generano automaticamente Deconstruct — utilizzare var (a, b) = record
  • I discards (_) ignorano i valori posizionali indesiderati nella destrutturazione
  • I property pattern ({Status: "X"}) sono più leggibili dei pattern posizionali per i record complessi

Domande Frequenti

La lezione «Uguaglianza per valore e destrutturazione» è gratuita?

Sì — il testo completo di «Uguaglianza per valore e destrutturazione» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.

Cosa imparerò in «Uguaglianza per valore e destrutturazione»?

Comprenda l'uguaglianza strutturale dei record, esegua l'override di Equals/GetHashCode e usi i pattern di destrutturazione. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Uguaglianza per valore e destrutturazione»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Tipi record: basi e sintassi
  2. Immutabilità con init e with
  3. Uguaglianza per valore e destrutturazione
  4. Record nel Domain-Driven Design
← Torna a C# Academy