Condividi tramite


L'espressione with - Mutazione non distruttiva crea un nuovo oggetto con proprietà modificate

Un'espressione with crea una copia del relativo operando con le proprietà e i campi specificati modificati. Usare la sintassi dell'inizializzatore di oggetti per specificare i membri da modificare e i relativi nuovi valori:

using System;

public class WithExpressionBasicExample
{
    public record NamedPoint(string Name, int X, int Y);

    public static void Main()
    {
        var p1 = new NamedPoint("A", 0, 0);
        Console.WriteLine($"{nameof(p1)}: {p1}");  // output: p1: NamedPoint { Name = A, X = 0, Y = 0 }
        
        var p2 = p1 with { Name = "B", X = 5 };
        Console.WriteLine($"{nameof(p2)}: {p2}");  // output: p2: NamedPoint { Name = B, X = 5, Y = 0 }
        
        var p3 = p1 with 
            { 
                Name = "C", 
                Y = 4 
            };
        Console.WriteLine($"{nameof(p3)}: {p3}");  // output: p3: NamedPoint { Name = C, X = 0, Y = 4 }

        Console.WriteLine($"{nameof(p1)}: {p1}");  // output: p1: NamedPoint { Name = A, X = 0, Y = 0 }

        var apples = new { Item = "Apples", Price = 1.19m };
        Console.WriteLine($"Original: {apples}");  // output: Original: { Item = Apples, Price = 1.19 }
        var saleApples = apples with { Price = 0.79m };
        Console.WriteLine($"Sale: {saleApples}");  // output: Sale: { Item = Apples, Price = 0.79 }
    }
}

L'operando sinistro di un'espressione with può essere un tipo di record. Può anche essere un tipo di struttura o un tipo anonimo.

Il riferimento al linguaggio C# documenta la versione rilasciata più di recente del linguaggio C#. Contiene anche la documentazione iniziale per le funzionalità nelle versioni di anteprima pubblica per la prossima versione del linguaggio di programmazione.

La documentazione identifica tutte le funzionalità introdotte nelle ultime tre versioni della lingua o nelle anteprime pubbliche correnti.

Suggerimento

Per trovare quando una funzionalità è stata introdotta per la prima volta in C#, vedere l'articolo sulla cronologia delle versioni del linguaggio C#.

Il risultato di un'espressione with ha lo stesso tipo di runtime dell'operando dell'espressione, come illustrato nell'esempio seguente:

using System;

public class InheritanceExample
{
    public record Point(int X, int Y);
    public record NamedPoint(string Name, int X, int Y) : Point(X, Y);

    public static void Main()
    {
        Point p1 = new NamedPoint("A", 0, 0);
        Point p2 = p1 with { X = 5, Y = 3 };
        Console.WriteLine(p2 is NamedPoint);  // output: True
        Console.WriteLine(p2);  // output: NamedPoint { X = 5, Y = 3, Name = A }
    }
}

Quando un membro è un tipo riferimento, la copia di tale membro copia solo il riferimento a tale istanza del membro. Sia l'operando copia che l'operando originale accedono alla stessa istanza di tipo riferimento. Nell'esempio seguente viene illustrato il comportamento:

using System;
using System.Collections.Generic;

public class ExampleWithReferenceType
{
    public record TaggedNumber(int Number, List<string> Tags)
    {
        public string PrintTags() => string.Join(", ", Tags);
    }

    public static void Main()
    {
        var original = new TaggedNumber(1, new List<string> { "A", "B" });

        var copy = original with { Number = 2 };
        Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
        // output: Tags of copy: A, B

        original.Tags.Add("C");
        Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
        // output: Tags of copy: A, B, C
    }
}

Semantica di copia personalizzata

Ogni tipo di classe di record ha un costruttore di copia. Un costruttore di copia è un costruttore con un singolo parametro del tipo di record contenitore. Copia lo stato dell'argomento in una nuova istanza di record. Quando si valuta un'espressione with , chiama il costruttore di copia per creare una nuova istanza di record basata su un record originale. Aggiorna quindi la nuova istanza con le modifiche specificate. Per impostazione predefinita, il compilatore sintetizza il costruttore di copia. Per personalizzare la semantica di copia del record, dichiarare in modo esplicito un costruttore di copia con il comportamento desiderato. Nell'esempio seguente viene aggiornato l'esempio precedente con un costruttore di copia esplicito. Il nuovo comportamento di copia copia gli elementi dell'elenco anziché un riferimento a un elenco quando viene copiato un record:

using System;
using System.Collections.Generic;

public class UserDefinedCopyConstructorExample
{
    public record TaggedNumber(int Number, List<string> Tags)
    {
        protected TaggedNumber(TaggedNumber original)
        {
            Number = original.Number;
            Tags = new List<string>(original.Tags);
        }

        public string PrintTags() => string.Join(", ", Tags);
    }

    public static void Main()
    {
        var original = new TaggedNumber(1, new List<string> { "A", "B" });

        var copy = original with { Number = 2 };
        Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
        // output: Tags of copy: A, B

        original.Tags.Add("C");
        Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
        // output: Tags of copy: A, B
    }
}

Non è possibile personalizzare la semantica di copia per i tipi di struttura.

Importante

Negli esempi precedenti tutte le proprietà sono indipendenti. Nessuna delle proprietà viene calcolata da altri valori di proprietà. Un'espressione with copia prima l'istanza di record esistente, quindi modifica le proprietà o i campi specificati nell'espressione with . Le proprietà calcolate nei record tipi devono essere calcolate in base all'accesso, non inizializzate al momento della creazione dell'istanza. In caso contrario, una proprietà potrebbe restituire il valore calcolato in base all'istanza originale, non alla copia modificata. Per altre informazioni, vedere l'articolo di riferimento sul linguaggio sui record tipi.

Specifica del linguaggio C#

Per maggiori informazioni, consultare le seguenti sezioni della proposta di funzionalità relativa ai record nota:

Vedere anche