Tipi di tupla (riferimenti per C#)Tuple types (C# reference)

Disponibile in C# 7,0 e versioni successive, la funzionalità Tuple offre una sintassi concisa per raggruppare più elementi dati in una struttura di dati semplice.Available in C# 7.0 and later, the tuples feature provides concise syntax to group multiple data elements in a lightweight data structure. Nell'esempio seguente viene illustrato come è possibile dichiarare una variabile di tupla, inizializzarla e accedere ai relativi membri dati:The following example shows how you can declare a tuple variable, initialize it, and access its data members:

(double, int) t1 = (4.5, 3);
Console.WriteLine($"Tuple with elements {t1.Item1} and {t1.Item2}.");
// Output:
// Tuple with elements 4.5 and 3.

(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.

Come illustrato nell'esempio precedente, per definire un tipo di tupla, è necessario specificare i tipi di tutti i relativi membri dati e, facoltativamente, i nomi dei campi.As the preceding example shows, to define a tuple type, you specify types of all its data members and, optionally, the field names. Non è possibile definire metodi in un tipo di tupla, ma è possibile usare i metodi forniti da .NET, come illustrato nell'esempio seguente:You cannot define methods in a tuple type, but you can use the methods provided by .NET, as the following example shows:

(double, int) t = (4.5, 3);
Console.WriteLine(t.ToString());
Console.WriteLine($"Hash code of {t} is {t.GetHashCode()}.");
// Output:
// (4.5, 3)
// Hash code of (4.5, 3) is 718460086.

A partire da C# 7,3, i tipi di tupla supportano gli operatori di uguaglianza == e != .Beginning with C# 7.3, tuple types support equality operators == and !=. Per ulteriori informazioni, vedere la sezione relativa all' uguaglianza delle tuple .For more information, see the Tuple equality section.

I tipi di tupla sono tipi valore; gli elementi della tupla sono campi pubblici.Tuple types are value types; tuple elements are public fields. Che rende i tipi di valore modificabili delle tuple.That makes tuples mutable value types.

Nota

La funzionalità Tuple richiede il System.ValueTuple tipo e i tipi generici correlati, ad esempio, System.ValueTuple<T1,T2> che sono disponibili in .NET Core e .NET Framework 4,7 e versioni successive.The tuples feature requires the System.ValueTuple type and related generic types (for example, System.ValueTuple<T1,T2>), which are available in .NET Core and .NET Framework 4.7 and later. Per usare le tuple in un progetto che ha come destinazione .NET Framework 4.6.2 o versione precedente, aggiungere il pacchetto NuGet System.ValueTuple al progetto.To use tuples in a project that targets .NET Framework 4.6.2 or earlier, add the NuGet package System.ValueTuple to the project.

È possibile definire tuple con un numero elevato arbitrario di elementi:You can define tuples with an arbitrary large number of elements:

var t = 
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26);
Console.WriteLine(t.Item26);  // output: 26

Casi d'uso delle tupleUse cases of tuples

Uno dei casi d'uso più comuni delle tuple è come tipo restituito del metodo.One of the most common use cases of tuples is as a method return type. Ovvero, anziché definire i out parametri del metodo, è possibile raggruppare i risultati del metodo in un tipo restituito della tupla, come illustrato nell'esempio seguente:That is, instead of defining out method parameters, you can group method results in a tuple return type, as the following example shows:

var xs = new[] { 4, 7, 9 };
var limits = FindMinMax(xs);
Console.WriteLine($"Limits of [{string.Join(" ", xs)}] are {limits.min} and {limits.max}");
// Output:
// Limits of [4 7 9] are 4 and 9

var ys = new[] { -9, 0, 67, 100 };
var (minimum, maximum) = FindMinMax(ys);
Console.WriteLine($"Limits of [{string.Join(" ", ys)}] are {minimum} and {maximum}");
// Output:
// Limits of [-9 0 67 100] are -9 and 100

(int min, int max) FindMinMax(int[] input)
{
    if (input is null || input.Length == 0)
    {
        throw new ArgumentException("Cannot find minimum and maximum of a null or empty array.");
    }

    var min = int.MaxValue;
    var max = int.MinValue;
    foreach (var i in input)
    {
        if (i < min)
        {
            min = i;
        }
        if (i > max)
        {
            max = i;
        }
    }
    return (min, max);
}

Come illustrato nell'esempio precedente, è possibile usare direttamente l'istanza di tupla restituita o decostruirla in variabili separate.As the preceding example shows, you can work with the returned tuple instance directly or deconstruct it in separate variables.

È inoltre possibile utilizzare tipi di tupla anziché tipi anonimi; ad esempio, nelle query LINQ.You can also use tuple types instead of anonymous types; for example, in LINQ queries. Per ulteriori informazioni, vedere scelta tra tipi anonimi e Tuple.For more information, see Choosing between anonymous and tuple types.

In genere, le tuple vengono utilizzate per raggruppare elementi di dati debolmente correlati.Typically, you use tuples to group loosely related data elements. Questo è in genere utile all'interno di metodi di utilità privati e interni.That is usually useful within private and internal utility methods. Nel caso di un'API pubblica, è consigliabile definire una classe o un tipo di struttura .In the case of public API, consider defining a class or a structure type.

Nomi dei campi di tuplaTuple field names

È possibile specificare in modo esplicito i nomi dei campi di tupla in un'espressione di inizializzazione della tupla o nella definizione di un tipo di tupla, come illustrato nell'esempio seguente:You can explicitly specify the names of tuple fields either in a tuple initialization expression or in the definition of a tuple type, as the following example shows:

var t = (Sum: 4.5, Count: 3);
Console.WriteLine($"Sum of {t.Count} elements is {t.Sum}.");

(double Sum, int Count) d = (4.5, 3);
Console.WriteLine($"Sum of {d.Count} elements is {d.Sum}.");

A partire da C# 7,1, se non si specifica un nome di campo, può essere dedotto dal nome della variabile corrispondente in un'espressione di inizializzazione della tupla, come illustrato nell'esempio seguente:Beginning with C# 7.1, if you don't specify a field name, it may be inferred from the name of the corresponding variable in a tuple initialization expression, as the following example shows:

var sum = 4.5;
var count = 3;
var t = (sum, count);
Console.WriteLine($"Sum of {t.count} elements is {t.sum}.");

Noto come inizializzatori di proiezione della tupla.That's known as tuple projection initializers. Il nome di una variabile non è proiettato su un nome di campo di tupla nei casi seguenti:The name of a variable isn't projected onto a tuple field name in the following cases:

  • Il nome candidato è un nome di membro di un tipo di tupla, ad esempio,, Item3 ToString o Rest .The candidate name is a member name of a tuple type, for example, Item3, ToString, or Rest.
  • Il nome candidato è un duplicato di un altro nome di campo di tupla, esplicito o implicito.The candidate name is a duplicate of another tuple field name, either explicit or implicit.

In questi casi è possibile specificare in modo esplicito il nome di un campo o accedere a un campo con il nome predefinito.In those cases you either explicitly specify the name of a field or access a field by its default name.

I nomi predefiniti dei campi di tupla sono Item1 , Item2 Item3 e così via.The default names of tuple fields are Item1, Item2, Item3 and so on. È sempre possibile usare il nome predefinito di un campo, anche quando un nome di campo viene specificato in modo esplicito o dedotto, come illustrato nell'esempio seguente:You can always use the default name of a field, even when a field name is specified explicitly or inferred, as the following example shows:

var a = 1;
var t = (a, b: 2, 3);
Console.WriteLine($"The 1st element is {t.Item1} (same as {t.a}).");
Console.WriteLine($"The 2nd element is {t.Item2} (same as {t.b}).");
Console.WriteLine($"The 3rd element is {t.Item3}.");
// Output:
// The 1st element is 1 (same as 1).
// The 2nd element is 2 (same as 2).
// The 3rd element is 3.

L' assegnazione di Tuple e i confronti di uguaglianza delle tuple non accettano nomi di campo.Tuple assignment and tuple equality comparisons don't take field names into account.

In fase di compilazione, il compilatore sostituisce i nomi di campo non predefiniti con i nomi predefiniti corrispondenti.At compile time, the compiler replaces non-default field names with the corresponding default names. Di conseguenza, i nomi di campo specificati in modo esplicito o dedotti non sono disponibili in fase di esecuzione.As a result, explicitly specified or inferred field names aren't available at run time.

Assegnazione e decostruzione di TupleTuple assignment and deconstruction

C# supporta l'assegnazione tra tipi di tupla che soddisfano entrambe le condizioni seguenti:C# supports assignment between tuple types that satisfy both of the following conditions:

  • entrambi i tipi di tupla hanno lo stesso numero di elementiboth tuple types have the same number of elements
  • per ogni posizione di tupla, il tipo dell'elemento di tupla a destra è uguale o convertibile in modo implicito nel tipo dell'elemento tupla a sinistra corrispondente.for each tuple position, the type of the right-hand tuple element is the same as or implicitly convertible to the type of the corresponding left-hand tuple element

I valori degli elementi di tupla vengono assegnati in base all'ordine degli elementi della tupla.Tuple element values are assigned following the order of tuple elements. I nomi dei campi di tupla vengono ignorati e non assegnati, come illustrato nell'esempio seguente:The names of tuple fields are ignored and not assigned, as the following example shows:

(int, double) t1 = (17, 3.14);
(double First, double Second) t2 = (0.0, 1.0);
t2 = t1;
Console.WriteLine($"{nameof(t2)}: {t2.First} and {t2.Second}");
// Output:
// t2: 17 and 3.14

(double A, double B) t3 = (2.0, 3.0);
t3 = t2;
Console.WriteLine($"{nameof(t3)}: {t3.A} and {t3.B}");
// Output:
// t3: 17 and 3.14

È anche possibile usare l'operatore = di assegnazione per decostruire un'istanza di tupla in variabili separate.You can also use the assignment operator = to deconstruct a tuple instance in separate variables. Questa operazione può essere eseguita in uno dei modi seguenti:You can do that in one of the following ways:

  • Dichiarare in modo esplicito il tipo di ogni variabile racchiusa tra parentesi:Explicitly declare the type of each variable inside parentheses:

    var t = ("post office", 3.6);
    (string destination, double distance) = t;
    Console.WriteLine($"Distance to {destination} is {distance} kilometers.");
    // Output:
    // Distance to post office is 3.6 kilometers.
    
  • Usare la var parola chiave all'esterno delle parentesi per dichiarare le variabili tipizzate in modo implicito e consentire al compilatore di dedurre i tipi:Use the var keyword outside the parentheses to declare implicitly typed variables and let the compiler infer their types:

    var t = ("post office", 3.6);
    var (destination, distance) = t;
    Console.WriteLine($"Distance to {destination} is {distance} kilometers.");
    // Output:
    // Distance to post office is 3.6 kilometers.
    
  • USA variabili esistenti:Use existing variables:

    var destination = string.Empty;
    var distance = 0.0;
    
    var t = ("post office", 3.6);
    (destination, distance) = t;
    Console.WriteLine($"Distance to {destination} is {distance} kilometers.");
    // Output:
    // Distance to post office is 3.6 kilometers.
    

Per ulteriori informazioni sulla decostruzione di tuple e altri tipi, vedere decostruzione di Tuple e altri tipi.For more information about deconstruction of tuples and other types, see Deconstructing tuples and other types.

Uguaglianza TupleTuple equality

A partire da C# 7.3, i tipi tupla supportano gli operatori == e !=.Beginning with C# 7.3, tuple types support the == and != operators. Questi operatori confrontano i membri dell'operando sinistro con i membri corrispondenti dell'operando destro che segue l'ordine degli elementi della tupla.These operators compare members of the left-hand operand with the corresponding members of the right-hand operand following the order of tuple elements.

(int a, byte b) left = (5, 10);
(long a, int b) right = (5, 10);
Console.WriteLine(left == right);  // output: True
Console.WriteLine(left != right);  // output: False

var t1 = (A: 5, B: 10);
var t2 = (B: 5, A: 10);
Console.WriteLine(t1 == t2);  // output: True
Console.WriteLine(t1 != t2);  // output: False

Come illustrato nell'esempio precedente, le == != operazioni e non prendono in considerazione i nomi dei campi di tupla.As the preceding example shows, the == and != operations don't take into account tuple field names.

Due tuple sono confrontabili quando sono soddisfatte entrambe le condizioni seguenti:Two tuples are comparable when both of the following conditions are satisfied:

  • Entrambe le tuple hanno lo stesso numero di elementi.Both tuples have the same number of elements. Ad esempio, t1 != t2 non compila se t1 e t2 hanno numeri di elementi diversi.For example, t1 != t2 doesn't compile if t1 and t2 have different numbers of elements.
  • Per ogni posizione di tupla, gli elementi corrispondenti dagli operandi di tupla a sinistra e a destra sono confrontabili con == gli != operatori e.For each tuple position, the corresponding elements from the left-hand and right-hand tuple operands are comparable with the == and != operators. Ad esempio, (1, (2, 3)) == ((1, 2), 3) non viene compilato perché 1 non è confrontabile con (1, 2) .For example, (1, (2, 3)) == ((1, 2), 3) doesn't compile because 1 is not comparable with (1, 2).

Gli == != operatori e confrontano le tuple in modalità di corto circuito.The == and != operators compare tuples in short-circuiting way. In altre termini, un'operazione viene arrestata non appena incontra una coppia di elementi non uguali o raggiunge le estremità delle tuple.That is, an operation stops as soon as it meets a pair of non equal elements or reaches the ends of tuples. Tuttavia, prima di qualsiasi confronto, vengono valutati tutti gli elementi della tupla, come illustrato nell'esempio seguente:However, before any comparison, all tuple elements are evaluated, as the following example shows:

Console.WriteLine((Display(1), Display(2)) == (Display(3), Display(4)));

int Display(int s)
{
    Console.WriteLine(s);
    return s;
}
// Output:
// 1
// 2
// 3
// 4
// False

Tuple come parametri outTuples as out parameters

In genere, si effettua il refactoring di un metodo che dispone di out parametri in un metodo che restituisce una tupla.Typically, you refactor a method that has out parameters into a method that returns a tuple. Tuttavia, esistono casi in cui un out parametro può essere di un tipo di tupla.However, there are cases in which an out parameter can be of a tuple type. Nell'esempio seguente viene illustrato come utilizzare le tuple come out parametri:The following example shows how to work with tuples as out parameters:

var limitsLookup = new Dictionary<int, (int Min, int Max)>()
{
    [2] = (4, 10),
    [4] = (10, 20),
    [6] = (0, 23)
};

if (limitsLookup.TryGetValue(4, out (int Min, int Max) limits))
{
    Console.WriteLine($"Found limits: min is {limits.Min}, max is {limits.Max}");
}
// Output:
// Found limits: min is 10, max is 20

Confronto tra tuple e System.TupleTuples vs System.Tuple

Le tuple C#, supportate dai System.ValueTuple tipi, sono diverse dalle tuple rappresentate dai System.Tuple tipi.C# tuples, which are backed by System.ValueTuple types, are different from tuples that are represented by System.Tuple types. Di seguito sono riportate le differenze principali:The main differences are as follows:

  • ValueTuple i tipi sono tipi di valore.ValueTuple types are value types. Tuple i tipi sono tipi di riferimento.Tuple types are reference types.
  • ValueTuple i tipi sono modificabili.ValueTuple types are mutable. Tuple i tipi non sono modificabili.Tuple types are immutable.
  • I membri dati di ValueTuple tipo sono campi.Data members of ValueTuple types are fields. I membri dati di Tuple tipo sono proprietà.Data members of Tuple types are properties.

Specifiche del linguaggio C#C# language specification

Per ulteriori informazioni, vedere le note sulla proposta di funzionalità seguenti:For more information, see the following feature proposal notes:

Vedi ancheSee also