Condividi tramite


Scelta tra tipi anonimi e tuple

La scelta del tipo appropriato comporta la considerazione dell'usabilità, delle prestazioni e dei compromessi rispetto ad altri tipi. I tipi anonimi sono disponibili a partire da C# 3.0, mentre i tipi generici System.Tuple<T1,T2> sono stati introdotti con .NET Framework 4.0. Da allora sono state introdotte nuove opzioni con il supporto a livello di linguaggio, come System.ValueTuple<T1,T2>, che, come suggerisce il nome, forniscono un tipo di valore con la flessibilità dei tipi anonimi. In questo articolo si apprenderà quando è opportuno scegliere un tipo rispetto all'altro.

Usabilità e funzionalità

I tipi anonimi sono stati introdotti in C# 3.0 con espressioni LINQ (Language-Integrated Query). Con LINQ, gli sviluppatori spesso proiettano i risultati delle query in tipi anonimi che contengono alcune proprietà selezionate dagli oggetti in uso. Si consideri il seguente esempio, che istanzia una matrice di oggetti DateTime e ne itera proiettandoli 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 di tupla (Riferimenti per C#) o Tuple (Visual Basic).For more information about tuples, see Tuple types (C# reference) or 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