Scelta tra tipi anonimi e tuple

Scegliere tra tipi anonimi, System.Tuple<T1,T2>e System.ValueTuple<T1,T2> in base a usabilità, prestazioni e compromessi. ValueTuple offre un tipo valore con la flessibilità dei tipi anonimi. Questo articolo illustra quando scegliere ogni tipo.

Usabilità e funzionalità

Con Language-Integrated Query (LINQ), spesso si proiettano i risultati delle query in tipi anonimi che contengono alcune proprietà selezionate dagli oggetti di origine. L'esempio seguente crea un'istanza di una matrice di DateTime oggetti e proietta ogni oggetto in un tipo anonimo con due proprietà.

var dates = new[]
{
    DateTime.UtcNow.AddHours(-1),
    DateTime.UtcNow,
    DateTime.UtcNow.AddHours(1),
};

foreach (var anonymous in
             dates.Select(
                 date => new { Formatted = $"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks }))
{
    Console.WriteLine($"Ticks: {anonymous.Ticks}, formatted: {anonymous.Formatted}");
}

I tipi anonimi vengono create tramite l'operatore new e i nomi e i tipi di proprietà vengono dedotti dalla dichiarazione. Se due o più inizializzatori di oggetti anonimi nello stesso assembly specificano una sequenza di proprietà nello stesso ordine e con gli stessi nomi e tipi, il compilatore considera gli oggetti come istanze dello stesso tipo. Condividono le stesse informazioni sul tipo generate dal compilatore.

Il frammento di codice C# precedente proietta un tipo anonimo con due proprietà, in modo analogo alla classe C# generata dal compilatore seguente:

internal sealed class f__AnonymousType0
{
    public string Formatted { get; }
    public long Ticks { get; }

    public f__AnonymousType0(string formatted, long ticks)
    {
        Formatted = formatted;
        Ticks = ticks;
    }
}

Per altre informazioni, vedere Tipi anonimi. La stessa funzionalità esiste con le tuple durante la proiezione nelle query LINQ, ed è possibile selezionare le proprietà nelle tuple. Queste tuple passano attraverso la query, esattamente come i tipi anonimi. Si consideri ora l'esempio seguente usando .System.Tuple<string, long>

var dates = new[]
{
    DateTime.UtcNow.AddHours(-1),
    DateTime.UtcNow,
    DateTime.UtcNow.AddHours(1),
};

foreach (var tuple in
            dates.Select(
                date => new Tuple<string, long>($"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks)))
{
    Console.WriteLine($"Ticks: {tuple.Item2}, formatted: {tuple.Item1}");
}

Con , l'istanza System.Tuple<T1,T2>espone le proprietà degli elementi numerati, ad esempio Item1, e Item2. Questi nomi di proprietà possono rendere più difficile comprendere la finalità dei valori delle proprietà, poiché il nome della proprietà fornisce solo un valore ordinale. Inoltre, i System.Tuple tipi sono tipi di riferimento class . Tuttavia System.ValueTuple<T1,T2> , è un tipo di valore struct . Il frammento di codice C# seguente usa ValueTuple<string, long> per proiettare in . In questo modo, assegna l'uso di una sintassi letterale.

var dates = new[]
{
    DateTime.UtcNow.AddHours(-1),
    DateTime.UtcNow,
    DateTime.UtcNow.AddHours(1),
};

foreach (var (formatted, ticks) in
            dates.Select(
                date => (Formatted: $"{date:MMM dd, yyyy at hh:mm zzz}", date.Ticks)))
{
    Console.WriteLine($"Ticks: {ticks}, formatted: {formatted}");
}

Per altre informazioni sulle tuple, vedere tipi Tuple (riferimenti per C#) o Tuples (Visual Basic).

Gli esempi precedenti sono tutti equivalenti a livello funzionale, ma esistono lievi differenze nell'usabilità e nelle implementazioni sottostanti.

Svantaggi

Potresti voler usare sempre ValueTuple al posto di Tuple e i tipi anonimi, ma ci sono dei compromessi che dovresti considerare. I ValueTuple tipi sono modificabili, mentre Tuple sono di sola lettura. I tipi anonimi possono essere usati negli alberi delle espressioni, mentre le tuple non possono. La tabella seguente offre una panoramica di alcune delle principali differenze.

Differenze principali

Nome Modificatore di accesso TIPO Nome membro personalizzato Supporto alla decostruzione Supporto dell'albero delle espressioni
Tipi anonimi internal class ✔️ ✔️
Tuple public class ✔️
ValueTuple public struct ✔️ ✔️

Serializzazione

Una considerazione importante quando si sceglie un tipo è se deve essere serializzata o meno. La serializzazione è il processo di conversione dello stato di un oggetto in un formato che può essere salvato in modo permanente o trasportato. Per altre informazioni, vedere Serializzazione. Quando la serializzazione è importante, la creazione di un class o struct è preferibile rispetto a tipi anonimi o tipo tupla.

Prestazioni

Le prestazioni tra questi tipi dipendono dallo scenario. L'impatto principale comporta il compromesso tra allocazioni e copia. Nella maggior parte degli scenari, l'impatto è ridotto. Quando possono verificarsi gravi impatti, è necessario prendere misure per informare la decisione.

Conclusione

In qualità di sviluppatore che sceglie tra tuple e tipi anonimi, esistono diversi fattori da considerare. In generale, se non si lavora con gli alberi delle espressioni e si ha familiarità con la sintassi delle tuple, allora scegli ValueTuple, poiché fornisce un tipo valore con la flessibilità di nominare le proprietà. Se lavorate con alberi delle espressioni e preferite denominare le proprietà, scegliete tipi anonimi. In caso contrario, usare Tuple.

Vedere anche