次の方法で共有


分解式 - タプルまたはその他のユーザー定義型のプロパティやフィールドを抽出する

分解式は、オブジェクトのインスタンスのデータ フィールドを抽出します。 個々のデータ要素は、次の例に示すように、それぞれ個別の変数に書き込まれます。

var tuple = (X: 1, Y: 2);
var (x, y) = tuple;

Console.WriteLine(x); // output: 1
Console.WriteLine(y); // output: 2

上記のコード スニペットは、2 つの整数値 XY を持つタプルを作成します。 2 番目のステートメントは、そのタプルを分解し、タプルの要素を個別の変数 xy に格納します。

タプルの分解

すべてのタプル型は、分解式をサポートしています。 タプルの分解では、タプルのすべての要素を抽出します。 タプル要素の一部のみが必要である場合は、次の例に示すように、未使用のタプル メンバーの破棄を使用します。

var tuple2 = (X: 0, Y: 1, Label: "The origin");
var (x2, _, _) = tuple2;

先ほどの例では、Ylabel のメンバーは破棄されます。 同じ分解式で複数の破棄を指定できます。 タプルのすべてのメンバーについて、破棄を使用できます。 次の例は、構文的には正しいですが、実用的ではありません。

var (_, _, _) = tuple2;

レコードの分解

プライマリ コンストラクターを持つレコード型は、位置指定パラメーターの分解をサポートします。 コンパイラは、プライマリ コンストラクターの位置指定パラメーターから自動的に生成されたプロパティの値を抽出する Deconstruct メソッドを自動的に生成します。 ただし、コンパイラが自動的に生成する Deconstruction メソッドは、レコード型内で明示的にプロパティとして宣言されたものは抽出しません。

次のコードに示す record は、SquareFeetAddress という 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 つの軸の値 XYZ を抽出するものです。 2 番目のメソッドは平面値 XY のみを分解するものです。 最初のメソッドの引数の数 (arity) は 3 で、2 番目のメソッドの引数の数は 2 です。

前のセクションでは、プライマリ コンストラクターを持つ Deconstruct 型に対して、コンパイラによって生成された record メソッドについて説明しました。 レコード型では、さらに多くの Deconstruct メソッドを宣言できます。 これらのメソッドでは、他のプロパティを追加したり、既定のプロパティの一部を削除したり、またはその両方を行うことができます。 また、コンパイラが自動的に生成するシグネチャと一致する Deconstruct を宣言することもできます。 そのような Deconstruct メソッドを宣言した場合、コンパイラはメソッドを自動的に生成しません。

コンパイラが分解式に対して一意の Deconstruct メソッドを特定できる限り、複数の Deconstruct メソッドを定義できます。 通常、同じ型に複数の Deconstruct メソッドを定義する場合は、パラメーターの数を変えます。 また、パラメーターの型を変えることで、複数の Deconstruct メソッドを定義することもできます。 ただし、Deconstruct メソッドを多用すると、コンパイラが適切なメソッドを特定できなくなり、予期しない結果を招く可能性があります。

C# 言語仕様

詳細については、C# 標準の分解のセクションを参照してください。

関連項目