Types Tuple (référence C#)
La fonctionnalité tuples fournit une syntaxe concise pour regrouper plusieurs éléments de données dans une structure de données légère. L’exemple suivant montre comment déclarer une variable tuple, l’initialiser et accéder à ses membres de données :
(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.
Comme l’illustre l’exemple précédent, pour définir un type tuple, vous spécifiez les types de tous ses membres de données et, éventuellement, les noms de champs. Vous ne pouvez pas définir de méthodes dans un type tuple, mais vous pouvez utiliser les méthodes fournies par .NET, comme l’illustre l’exemple suivant :
(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.
Les types tuple prennent en charge les opérateurs==
d’égalité et !=
. Pour plus d’informations, consultez la section d’égalité de Tuple .
Les types tuple sont des types valeur ; Les éléments tuple sont des champs publics. Cela rend les tuples mutables types valeur.
Notes
La fonctionnalité tuples nécessite le System.ValueTuple type et les types génériques associés (par exemple, System.ValueTuple<T1,T2>), qui sont disponibles dans .NET Core et .NET Framework 4.7 et versions ultérieures. Pour utiliser des tuples dans un projet qui cible .NET Framework 4.6.2 ou version antérieure, ajoutez le package System.ValueTuple
NuGet au projet.
Vous pouvez définir des tuples avec un grand nombre arbitraire d’éléments :
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
Cas d’usage de tuples
L’un des cas d’usage les plus courants de tuples est un type de retour de méthode. Autrement dit, au lieu de définir out
des paramètres de méthode, vous pouvez regrouper des résultats de méthode dans un type de retour tuple, comme l’illustre l’exemple suivant :
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);
}
Comme l’illustre l’exemple précédent, vous pouvez utiliser l’instance de tuple retournée directement ou la déconstructer dans des variables distinctes.
Vous pouvez également utiliser des types tuple au lieu de types anonymes ; par exemple, dans les requêtes LINQ. Pour plus d’informations, consultez Choisir entre les types anonymes et tuples.
En règle générale, vous utilisez des tuples pour regrouper des éléments de données faiblement associés. Cela est généralement utile dans les méthodes d’utilitaire privé et interne. Dans le cas de l’API publique, envisagez de définir une classe ou un type de structure .
Noms des champs tuples
Vous pouvez spécifier explicitement les noms des champs tuples dans une expression d’initialisation de tuple ou dans la définition d’un type tuple, comme l’illustre l’exemple suivant :
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}.");
Si vous ne spécifiez pas de nom de champ, il peut être déduit du nom de la variable correspondante dans une expression d’initialisation de tuple, comme l’illustre l’exemple suivant :
var sum = 4.5;
var count = 3;
var t = (sum, count);
Console.WriteLine($"Sum of {t.count} elements is {t.sum}.");
C’est ce que l’on appelle des initialiseurs de projection de tuple. Le nom d’une variable n’est pas projeté sur un nom de champ tuple dans les cas suivants :
- Le nom du candidat est un nom de membre d’un type tuple, par exemple,
Item3
,ToString
ouRest
. - Le nom du candidat est un doublon d’un autre nom de champ tuple, explicite ou implicite.
Dans ces cas, vous spécifiez explicitement le nom d’un champ ou accédez à un champ par son nom par défaut.
Les noms par défaut des champs tuple sont Item1
, Item3
Item2
et ainsi de suite. Vous pouvez toujours utiliser le nom par défaut d’un champ, même lorsqu’un nom de champ est spécifié explicitement ou déduit, comme l’illustre l’exemple suivant :
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’affectation de tuples et les comparaisons d’égalité de tuples ne prennent pas en compte les noms de champs.
Au moment de la compilation, le compilateur remplace les noms de champs non par défaut par les noms par défaut correspondants. Par conséquent, les noms de champs spécifiés ou déduits explicitement ne sont pas disponibles au moment de l’exécution.
Conseil
Activez la règle de style de code .NET IDE0037 pour définir une préférence sur les noms de champs tuples déduits ou explicites.
Affectation et déconstruction de tuple
C# prend en charge l’affectation entre les types tuple qui répondent aux deux conditions suivantes :
- les deux types tuple ont le même nombre d’éléments
- pour chaque position de tuple, le type de l’élément tuple de droite est identique ou implicitement convertible au type de l’élément tuple de gauche correspondant
Les valeurs d’élément tuple sont attribuées en suivant l’ordre des éléments de tuple. Les noms des champs tuple sont ignorés et non attribués, comme l’illustre l’exemple suivant :
(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
Vous pouvez également utiliser l’opérateur =
d’affectation pour déconstructer une instance de tuple dans des variables distinctes. Vous pouvez le faire de l’une des manières suivantes :
Déclarez explicitement le type de chaque variable entre parenthèses :
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.
Utilisez le
var
mot clé en dehors des parenthèses pour déclarer des variables implicitement typées et laisser le compilateur déduire leurs 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.
Utilisez des variables existantes :
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.
Pour plus d’informations sur la déconstruction des tuples et d’autres types, consultez Déconstruction des tuples et d’autres types.
Égalité des tuples
Les types tuple prennent en charge les opérateurs et !=
les ==
opérateurs. Ces opérateurs comparent les membres de l’opérande de gauche avec les membres correspondants de l’opérande de droite en suivant l’ordre des éléments tuples.
(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
Comme l’illustre l’exemple précédent, les opérations et !=
les opérations ne prennent pas en compte les ==
noms de champs de tuple.
Deux tuples sont comparables lorsque les deux conditions suivantes sont satisfaites :
- Les deux tuples ont le même nombre d’éléments. Par exemple,
t1 != t2
ne se compile pas sit1
ett2
a différents nombres d’éléments. - Pour chaque position de tuple, les éléments correspondants des opérandes tuples de gauche et de droite sont comparables aux
==
opérateurs et!=
aux opérateurs. Par exemple,(1, (2, 3)) == ((1, 2), 3)
ne se compile pas, car1
elle n’est pas comparable à(1, 2)
.
Les ==
opérateurs et !=
les opérateurs comparent les tuples de manière à court-circuit. Autrement dit, une opération s’arrête dès qu’elle rencontre une paire d’éléments non égaux ou atteint les extrémités des tuples. Toutefois, avant toute comparaison, tous les éléments tuples sont évalués, comme l’illustre l’exemple suivant :
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
Tuples en tant que paramètres sortants
En règle générale, vous refactorisez une méthode qui contient out
des paramètres dans une méthode qui retourne un tuple. Toutefois, il existe des cas dans lesquels un out
paramètre peut être d’un type tuple. L’exemple suivant montre comment utiliser des tuples en tant que out
paramètres :
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
Tuples vs System.Tuple
Les tuples C#, qui sont soutenus par System.ValueTuple des types, sont différents des tuples représentés par System.Tuple les types. Les principales différences sont les suivantes :
System.ValueTuple
les types sont des types valeur.System.Tuple
les types sont des types référence.System.ValueTuple
les types sont mutables.System.Tuple
les types sont immuables.- Les membres de données de
System.ValueTuple
types sont des champs. Les membres de données deSystem.Tuple
types sont des propriétés.
spécification du langage C#
Pour plus d’informations, consultez les notes de proposition de fonctionnalités suivantes :
- Inférer des noms de tuples (appelés initialiseurs de projection de tuple)
==
Prise en charge et!=
sur les types tuple