分解式 - タプルまたはその他のユーザー定義型のプロパティやフィールドを抽出する
分解式は、オブジェクトのインスタンスのデータ フィールドを抽出します。 個々のデータ要素は、次の例に示すように、それぞれ個別の変数に書き込まれます。
var tuple = (X: 1, Y: 2);
var (x, y) = tuple;
Console.WriteLine(x); // output: 1
Console.WriteLine(y); // output: 2
上記のコード スニペットは、2 つの整数値 X
と Y
を持つタプルを作成します。 2 番目のステートメントは、そのタプルを分解し、タプルの要素を個別の変数 x
と y
に格納します。
タプルの分解
すべてのタプル型は、分解式をサポートしています。 タプルの分解では、タプルのすべての要素を抽出します。 タプル要素の一部のみが必要である場合は、次の例に示すように、未使用のタプル メンバーの破棄を使用します。
var tuple2 = (X: 0, Y: 1, Label: "The origin");
var (x2, _, _) = tuple2;
先ほどの例では、Y
と label
のメンバーは破棄されます。 同じ分解式で複数の破棄を指定できます。 タプルのすべてのメンバーについて、破棄を使用できます。 次の例は、構文的には正しいですが、実用的ではありません。
var (_, _, _) = tuple2;
レコードの分解
プライマリ コンストラクターを持つレコード型は、位置指定パラメーターの分解をサポートします。 コンパイラは、プライマリ コンストラクターの位置指定パラメーターから自動的に生成されたプロパティの値を抽出する Deconstruct
メソッドを自動的に生成します。 ただし、コンパイラが自動的に生成する Deconstruction
メソッドは、レコード型内で明示的にプロパティとして宣言されたものは抽出しません。
次のコードに示す record
は、SquareFeet
と Address
という 2 つの位置指定プロパティと、もう 1 つの RealtorNotes
というプロパティを宣言しています。
public record House(int SquareFeet, string Address)
{
public required string RealtorNotes { get; set; }
}
House
オブジェクトを分解するとき、次の例に示すように、位置指定プロパティのみが分解対象となります。
var house = new House(1000, "123 Coder St.")
{
RealtorNotes = """
This is a great starter home, with a separate room that's a great home office setup.
"""
};
var (squareFeet, address) = house;
Console.WriteLine(squareFeet); // output: 1000
Console.WriteLine(address); // output: 123 Coder St.
Console.WriteLine(house.RealtorNotes);
この動作を利用して、コンパイラが生成する Deconstruct
メソッドに、レコード型のどのプロパティを含めるかを指定できます。
Deconstruct
メソッドを宣言する
宣言するあらゆるクラス、構造体、またはインターフェイスに分解機能を実装できます。 そのためには、型内で Deconstruct
メソッドを 1 つ以上宣言するか、その型の拡張メソッドとして宣言します。 分解式は void Deconstruct(out var p1, ..., out var pn)
メソッドを呼び出します。 Deconstruct
メソッドはインスタンス メソッドまたは拡張メソッドのいずれかになります。 Deconstruct
メソッドの各パラメーターの型は、分解式の対応する引数の型と一致する必要があります。 分解式では、各引数の値が Deconstruct
メソッドの対応する out
パラメーターの値に代入されます。 分解式に一致する Deconstruct
メソッドが複数ある場合、コンパイラはあいまいさに関するエラーを報告します。
次のコードでは、2 つの Deconstruct
メソッドを定義した Point3D
構造体を宣言しています。
public struct Point3D
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public void Deconstruct(out int x, out int y, out int z)
{
x = X;
y = Y;
z = Z;
}
public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
}
最初のメソッドは 3 つの軸の値 X
、Y
、Z
を抽出するものです。 2 番目のメソッドは平面値 X
と Y
のみを分解するものです。 最初のメソッドの引数の数 (arity) は 3 で、2 番目のメソッドの引数の数は 2 です。
前のセクションでは、プライマリ コンストラクターを持つ Deconstruct
型に対して、コンパイラによって生成された record
メソッドについて説明しました。 レコード型では、さらに多くの Deconstruct
メソッドを宣言できます。 これらのメソッドでは、他のプロパティを追加したり、既定のプロパティの一部を削除したり、またはその両方を行うことができます。 また、コンパイラが自動的に生成するシグネチャと一致する Deconstruct
を宣言することもできます。 そのような Deconstruct
メソッドを宣言した場合、コンパイラはメソッドを自動的に生成しません。
コンパイラが分解式に対して一意の Deconstruct
メソッドを特定できる限り、複数の Deconstruct
メソッドを定義できます。 通常、同じ型に複数の Deconstruct
メソッドを定義する場合は、パラメーターの数を変えます。 また、パラメーターの型を変えることで、複数の Deconstruct
メソッドを定義することもできます。 ただし、Deconstruct
メソッドを多用すると、コンパイラが適切なメソッドを特定できなくなり、予期しない結果を招く可能性があります。
C# 言語仕様
詳細については、C# 標準の分解のセクションを参照してください。
関連項目
.NET