Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Функция кортежей предоставляет краткий синтаксис для группировки нескольких элементов данных в упрощенной структуре данных.
Справочные документы на языке C#, выпущенные последней версией языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.
Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.
Совет
Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей по журналу версий языка C#.
В следующем примере показано, как можно объявить переменную кортежа, инициализировать ее и получить доступ к ее элементам данных.
(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.
Как показано в предыдущем примере, чтобы определить тип кортежа, необходимо указать типы всех его элементов данных и, при необходимости, имена полей. Невозможно определить методы в типе кортежа, но можно использовать методы, предоставляемые .NET, как показано в следующем примере:
(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.
Типы кортежей поддерживают операторы== равенства и !=. Дополнительные сведения см. в разделе Равенство кортежей.
Типы кортежей являются типами значений, а элементы кортежа — общедоступными полями. Эта конструкция делает кортежи изменяемыми типами значений.
Кортежи можно определить с произвольным большим количеством элементов:
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
Варианты использования кортежей
Одним из наиболее распространенных вариантов использования кортежей является тип возвращаемого метода. Вместо определения out параметров метода метод группы приводит к типу возвращаемого кортежа, как показано в следующем примере:
int[] xs = new int[] { 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
int[] ys = new int[] { -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.");
}
// Initialize min to MaxValue so every value in the input
// is less than this initial value.
var min = int.MaxValue;
// Initialize max to MinValue so every value in the input
// is greater than this initial value.
var max = int.MinValue;
foreach (var i in input)
{
if (i < min)
{
min = i;
}
if (i > max)
{
max = i;
}
}
return (min, max);
}
Как показано в предыдущем примере, с возвращаемым экземпляром кортежа можно работать напрямую или деконструировать его в отдельные переменные.
Типы кортежей можно также использовать вместо анонимных типов, например в запросах LINQ. Дополнительные сведения см. в статье Выбор между анонимными типами и кортежами.
Как правило, используйте кортежи для группирования слабо связанных элементов данных. В общедоступных API рекомендуется определить класс или тип структуры .
Имена полей кортежей
Вы явно указываете имена полей кортежей в выражении инициализации кортежа или в определении типа кортежа, как показано в следующем примере:
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}.");
Если имя поля не указано, компилятор может вывести его из имени соответствующей переменной в выражении инициализации кортежа, как показано в следующем примере:
var sum = 4.5;
var count = 3;
var t = (sum, count);
Console.WriteLine($"Sum of {t.count} elements is {t.sum}.");
Эта функция называется инициализаторами проекции кортежей. Имя переменной не проецируется на имя поля кортежа в следующих случаях:
- Имя кандидата — это имя элемента типа кортежа, например
Item3,ToStringилиRest. - Имя кандидата является дубликатом другого имени поля кортежа, явного или неявного.
В предыдущих случаях можно явно указать имя поля или получить доступ к полю по умолчанию.
Имена полей кортежа по умолчанию: Item1, Item3Item2и т. д. Всегда можно использовать имя поля по умолчанию, даже если имя поля указано явно или является выводимым, как показано в следующем примере.
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.
Имена полей не учитываются при присваивании кортежа и сравнении кортежей на равенство.
Во время компиляции компилятор заменяет имена полей не по умолчанию соответствующими именами по умолчанию. В результате явно указанные или выводимые имена полей будут недоступны во время выполнения.
Совет
Включите правило стиля кода .NET IDE0037 , чтобы задать предпочтения для выводимых или явных имен полей кортежей.
Начиная с C# 12, можно указать псевдоним для типа кортежа с директивойusing. В следующем примере добавляется global using псевдоним для типа кортежа с двумя целыми значениями допустимого Min и Max значения:
global using BandPass = (int Min, int Max);
После объявления псевдонима можно использовать BandPass имя в качестве псевдонима для этого типа кортежа:
BandPass bracket = (40, 100);
Console.WriteLine($"The bandpass filter is {bracket.Min} to {bracket.Max}");
Псевдоним не вводит новый тип, но создает синоним только для существующего типа. Вы можете деконструировать кортеж, объявленный псевдонимом BandPass так же, как и с его базовым типом кортежа:
(int a , int b) = bracket;
Console.WriteLine($"The bracket is {a} to {b}");
Как и при назначении кортежа или деконструкции, имена элементов кортежа не должны соответствовать; Типы выполняются.
Аналогичным образом можно использовать второй псевдоним с одинаковыми типами arity и членов взаимозаменяемо с исходным псевдонимом. Можно объявить второй псевдоним:
using Range = (int Minimum, int Maximum);
Кортеж можно назначить RangeBandPass кортеже. Как и во всех назначениях кортежей, имена полей не должны совпадать, только типы и arity.
Range r = bracket;
Console.WriteLine($"The range is {r.Minimum} to {r.Maximum}");
Псевдоним для типа кортежа предоставляет более семантические сведения при использовании кортежей. Он не вводит новый тип. Чтобы обеспечить безопасность типов, вместо этого следует объявить позиционный record элемент.
Присваивание и деконструкция кортежей
В C# поддерживается присваивание между типами кортежей, которые соответствуют обоим следующим условиям:
- Оба типа кортежей имеют одинаковое количество элементов.
- Для каждой позиции кортежа тип правого кортежа совпадает с типом соответствующего левого элемента кортежа.
Назначьте значения элементов кортежа, следуя порядку элементов кортежа. Процесс назначения игнорирует имена полей кортежей, как показано в следующем примере:
(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
Используйте оператор = назначения для деконструкции экземпляра кортежа в отдельные переменные. Это можно сделать различными способами:
Вы можете использовать ключевое слово
varза пределами круглых скобок, чтобы объявить неявно типизированные переменные и позволить компилятору вывести их типы.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.Вы можете явно объявить тип каждой переменной в скобках.
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.Объявите некоторые типы явно и другие типы неявно (с
var) внутри скобки:var t = ("post office", 3.6); (var destination, double distance) = t; Console.WriteLine($"Distance to {destination} is {distance} kilometers."); // Output: // Distance to post office is 3.6 kilometers.Вы можете использовать существующие переменные.
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.
Назначение деконструкционного выражения может включать как существующие переменные, так и переменные, объявленные в объявлении деконструкции.
Вы также можете объединить деконструкцию с сопоставлением шаблонов, чтобы проверить характеристики полей в кортеже. В следующем примере выполняется цикл по нескольким целым числам и выводится число, которое делится на 3. Он деконструирует результат Int32.DivRem кортежа и соответствует Remainder 0:
for (int i = 4; i < 20; i++)
{
if (Math.DivRem(i, 3) is ( Quotient: var q, Remainder: 0 ))
{
Console.WriteLine($"{i} is divisible by 3, with quotient {q}");
}
}
Подробнее о деконструкции кортежей с помощью и других типов см. в статье Деконструкция кортежей и других типов.
Равенство кортежей
Типы кортежей == поддерживают операторы и != операторы. Эти операторы сравнивают элементы левого операнда с соответствующими элементами правого операнда в соответствии с порядком расположения элементов кортежа.
(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
Как показано в предыдущем примере, == имена != полей кортежа не учитываются.
Два кортежа сравнимы, если выполнены оба следующих условия:
- оба кортежа содержат одинаковое количество элементов. Например,
t1 != t2не компилируется, еслиt1иt2имеют разное количество элементов. - Для каждой позиции кортежа соответствующие элементы из операндов слева и правой руки сравниваются с помощью
==операторов и!=операторов. Например, не компилируется,(1, (2, 3)) == ((1, 2), 3)так как1не сравнивается с(1, 2).
Операторы ==!= сравнивают кортежи в коротком канале. Это значит, что операция останавливается, как только она соответствует паре неравных элементов или достигает конца кортежей. Однако перед любым сравнением все элементы кортежа вычисляются, как показано в следующем примере.
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
Кортежи как параметры вывода
Как правило, вы выполняете рефакторинг метода, имеющего параметры out, в метод, возвращающий кортеж. Однако в некоторых случаях out параметр может быть типом кортежа. В следующем примере показано, как работать с кортежами в виде параметров out.
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
Кортежи и System.Tuple
Кортежи C# используют типы и отличаются System.ValueTuple от кортежей, использующих System.Tuple типы. Основными отличиями являются:
- Типы
System.ValueTupleявляются типами значений. ТипыSystem.Tupleявляются ссылочными типами. - Типы
System.ValueTupleявляются изменяемыми. ТипыSystem.Tupleявляются неизменяемыми. - Элементами данных типов
System.ValueTupleявляются поля. Элементами данных типовSystem.Tupleявляются свойства.
Спецификация языка C#
Дополнительные сведения см. в разделе: