タプル型 (C# リファレンス)Tuple types (C# reference)

C# 7.0 以降で利用できる "タプル" 機能により、軽量データ構造に複数のデータ要素をグループ化するための簡潔な構文が提供されています。Available in C# 7.0 and later, the tuples feature provides concise syntax to group multiple data elements in a lightweight data structure. 次の例は、タプル変数を宣言して初期化し、そのデータ メンバーにアクセスする方法を示しています。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.

前の例で示したように、タプル型を定義するには、すべてのデータ メンバーの型と、必要に応じてフィールド名を指定します。As the preceding example shows, to define a tuple type, you specify types of all its data members and, optionally, the field names. タプル型でメソッドを定義することはできませんが、次の例に示すように、.NET によって提供されるメソッドを使用できます。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.

C# 7.3 以降では、タプル型で等値演算子 ==!= がサポートされます。Beginning with C# 7.3, tuple types support equality operators == and !=. 詳しくは、「タプルの等値性」セクションをご覧ください。For more information, see the Tuple equality section.

タプル型は値型であり、タプル要素はパブリック フィールドです。Tuple types are value types; tuple elements are public fields. そのため、タプルは "変更可能な" 値の型になります。That makes tuples mutable value types.

注意

タプルの機能には、System.ValueTuple 型と、.NET Core と .NET Framework 4.7 以降で使用できる、関連のジェネリック型 (たとえば、System.ValueTuple<T1,T2>) が必要です。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. 4.6.2 以前の .NET Framework を対象とするプロジェクトでタプルを使用するには、NuGet パッケージ System.ValueTuple をプロジェクトに追加します。To use tuples in a project that targets .NET Framework 4.6.2 or earlier, add the NuGet package System.ValueTuple to the project.

任意の多数の要素を持つタプルを定義できます。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

タプルのユース ケースUse cases of tuples

特に一般的なタプルのユース ケースの 1 つが、メソッドの戻り値の型です。One of the most common use cases of tuples is as a method return type. つまり、out メソッド パラメーターを定義するのではなく、次の例のようにメソッドの結果をタプルの戻り値の型でグループ化できます。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);
}

前の例で示したように、返されたタプルのインスタンスを直接操作することも、別の変数に分解することもできます。As the preceding example shows, you can work with the returned tuple instance directly or deconstruct it in separate variables.

タプル型は匿名型の代わりに、たとえば LINQ クエリで使用することもできます。You can also use tuple types instead of anonymous types; for example, in LINQ queries. 詳細については、「匿名型またはタプル型の選択」を参照してください。For more information, see Choosing between anonymous and tuple types.

通常、タプルは関連性の低いデータ要素をグループ化するために使用します。Typically, you use tuples to group loosely related data elements. これは通常、非公開および内部のユーティリティ メソッド内で役に立ちます。That is usually useful within private and internal utility methods. パブリック API の場合は、クラスまたは構造体型を定義することを検討してください。In the case of public API, consider defining a class or a structure type.

タプルのフィールド名Tuple field names

次の例に示すように、タプルの初期化式またはタプルの型の定義でタプル フィールドの名前を明示的に指定できます。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}.");

C# 7.1 以降では、フィールド名を指定しない場合、次の例に示すように、タプルの初期化式で対応する変数の名前からそれが推論される場合があります。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}.");

これはタプル プロジェクション初期化子と呼ばれます。That's known as tuple projection initializers. 変数の名前は、次の場合、タプル フィールド名に投影されません。The name of a variable isn't projected onto a tuple field name in the following cases:

  • 候補名が Item3ToStringRest などのタプル型のメンバー名である。The candidate name is a member name of a tuple type, for example, Item3, ToString, or Rest.
  • 候補名が、別のタプル フィールド名 (明示的または暗黙的のいずれか) の複製である。The candidate name is a duplicate of another tuple field name, either explicit or implicit.

このような場合は、フィールドの名前を明示的に指定するか、既定の名前でフィールドにアクセスします。In those cases you either explicitly specify the name of a field or access a field by its default name.

タプル フィールドの既定の名前は、Item1Item2Item3 などです。The default names of tuple fields are Item1, Item2, Item3 and so on. 次の例に示すように、フィールド名が明示的に指定されていたり推論されていたりする場合でも、フィールドの既定の名前をいつでも使用できます。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.

タプルの代入タプルの等価比較では、フィールド名が考慮されません。Tuple assignment and tuple equality comparisons don't take field names into account.

コンパイル時に、コンパイラは既定以外のフィールド名を、対応する既定の名前に置き換えます。At compile time, the compiler replaces non-default field names with the corresponding default names. このため、明示的に指定された、または推論されたフィールド名は実行時に使用できません。As a result, explicitly specified or inferred field names aren't available at run time.

タプルの代入と分解Tuple assignment and deconstruction

C# では、次の両方の条件を満たすタプル型間の代入がサポートされます。C# supports assignment between tuple types that satisfy both of the following conditions:

  • 両方のタプル型に、同じ数の要素があるboth tuple types have the same number of elements
  • タプルのそれぞれの位置で、右側のタプル要素の型が対応する左側のタプル要素の型と同じか、暗黙的に変換可能である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

タプル要素の値は、タプル要素の順序に従って代入されます。Tuple element values are assigned following the order of tuple elements. 次の例に示すように、タプル フィールドの名前は無視され、代入されません。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

また、代入演算子 = を使用して、別の変数でタプル インスタンスを "分解する" こともできます。You can also use the assignment operator = to deconstruct a tuple instance in separate variables. これは、次の方法のいずれかで実行できます。You can do that in one of the following ways:

  • かっこ内の各変数の型を明示的に宣言する。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.
    
  • かっこの外にある var キーワードを使用して、暗黙的に型指定された変数を宣言し、コンパイラによってその型が推論されるようにする。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.
    
  • 既存の変数を使用する。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.
    

タプルとその他の型の分解の詳細については、「タプルとその他の型の分解」を参照してください。For more information about deconstruction of tuples and other types, see Deconstructing tuples and other types.

タプルの等値性Tuple equality

C# 7.3 以降では、タプル型で == および != 演算子がサポートされます。Beginning with C# 7.3, tuple types support the == and != operators. これらの演算子により、左側のオペランドのメンバーが、タプル要素の順序に従って、右側のオペランドの対応するメンバーと比較されます。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

前の例で示したように、==!= の演算では、タプルのフィールド名は考慮されません。As the preceding example shows, the == and != operations don't take into account tuple field names.

2 つのタプルは、次の両方の条件が満たされている場合に比較できます。Two tuples are comparable when both of the following conditions are satisfied:

  • 両方のタプルが、同じ数の要素を保持している。Both tuples have the same number of elements. たとえば、t1t2 の要素数が異なる場合、t1 != t2 はコンパイルされません。For example, t1 != t2 doesn't compile if t1 and t2 have different numbers of elements.
  • タプルの位置ごとに、左側と右側のタプルのオペランドの対応する要素が、==!= の演算子と比較されます。For each tuple position, the corresponding elements from the left-hand and right-hand tuple operands are comparable with the == and != operators. たとえば、1(1, 2) と比較できないため、(1, (2, 3)) == ((1, 2), 3) はコンパイルされません。For example, (1, (2, 3)) == ((1, 2), 3) doesn't compile because 1 is not comparable with (1, 2).

==!= の演算子によって、タプルがショートサーキット方式で比較されます。The == and != operators compare tuples in short-circuiting way. つまり、等しくない要素のペアか、タプルの端に到達するとすぐに、演算が停止します。That is, an operation stops as soon as it meets a pair of non equal elements or reaches the ends of tuples. ただし、比較の前には必ず、次の例に示すように、"すべての" タプル要素が評価されます。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

out パラメーターとしてのタプルTuples as out parameters

通常は、out パラメーターを持つメソッドを、タプルを返すメソッドにリファクタリングします。Typically, you refactor a method that has out parameters into a method that returns a tuple. ただし、out パラメーターがタプル型である場合もあります。However, there are cases in which an out parameter can be of a tuple type. 次の例に、out パラメーターとしてタプルを操作する方法を示します。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

タプルと System.TupleTuples vs System.Tuple

System.ValueTuple 型によってサポートされる C# のタプルは、System.Tuple タプルで表されるタプルとは異なります。C# tuples, which are backed by System.ValueTuple types, are different from tuples that are represented by System.Tuple types. 主な相違点は、次のとおりです。The main differences are as follows:

  • ValueTuple 型は値の型です。ValueTuple types are value types. Tuple 型は参照型です。Tuple types are reference types.
  • ValueTuple 型は変更可能です。ValueTuple types are mutable. Tuple 型は変更不可能です。Tuple types are immutable.
  • ValueTuple 型のデータ メンバーはフィールドです。Data members of ValueTuple types are fields. Tuple 型のデータ メンバーはプロパティです。Data members of Tuple types are properties.

C# 言語仕様C# language specification

詳しくは、次の機能提案メモをご覧ください。For more information, see the following feature proposal notes:

関連項目See also