Bewerken

Delen via


Deconstruction expression - Extract properties of fields from a tuple or other user-defined type

A deconstruction expression extracts data fields from an instance of an object. Each discrete data element is written to a distinct variable, as shown in the following example:

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

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

The preceding code snippet creates a tuple that has two integer values, X and Y. The second statement deconstructs that tuple and stores the tuple elements in discrete variables x and y.

Tuple deconstruction

All tuple types support deconstruction expressions. Tuple deconstruction extracts all the tuple's elements. If you only want some of the tuple elements, use a discard for the unused tuple members, as shown in the following example:

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

In the preceding example, the Y and label members are discarded. You can specify multiple discards in the same deconstruction expression. You can use discards for all the members of the tuple. The following example is legal, although not useful:

var (_, _, _) = tuple2;

Record deconstruction

Record types that have a primary constructor support deconstruction for positional parameters. The compiler synthesizes a Deconstruct method that extracts the properties synthesized from positional parameters in the primary constructor. The compiler-synthesized Deconstruction method doesn't extract properties declared as properties in the record type.

The record shown in the following code declares two positional properties, SquareFeet and Address, along with another property, RealtorNotes:

public record House(int SquareFeet, string Address)
{
    public required string RealtorNotes { get; set; }
}

When you deconstruct a House object, all positional properties, and only positional properties, are deconstructed, as shown in the following example:

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);

You can make use of this behavior to specify which properties of your record types are part of the compiler-synthesized Deconstruct method.

Declare Deconstruct methods

You can add deconstruction support to any class, struct, or interface you declare. You declare one or Deconstruct methods in your type, or as extension methods on that type. A deconstruction expression calls a method void Deconstruct(out var p1, ..., out var pn). The Deconstruct method can be either an instance method or an extension method. The type of each parameter in the Deconstruct method must match the type of the corresponding argument in the deconstruction expression. The deconstruction expression assigns the value of each argument to the value of the corresponding out parameter in the Deconstruct method. If multiple Deconstruct methods match the deconstruction expression, the compiler reports an error for the ambiguity.

The following code declares a Point3D struct that has two Deconstruct methods:

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;
    }
}

The first method supports deconstruction expressions that extract all three axis values: X, Y, and Z. The second method supports deconstructing only the planar values: X and Y. The first method has an arity of 3; the second has an arity of 2.

The preceding section described the compiler-synthesized Deconstruct method for record types with a primary constructor. You can declare more Deconstruct methods in record types. These methods can either add other properties, remove some of the default properties, or both. You can also declare a Deconstruct that matches the compiler-synthesized signature. If you declare such a Deconstruct method, the compiler doesn't synthesize one.

Multiple Deconstruct methods are allowed as long as the compiler can determine one unique Deconstruct method for a deconstruction expression. Typically, multiple Deconstruct methods for the same type have different numbers of parameters. You can also create multiple Deconstruct methods that differ by parameter types. However, in many cases, too many Deconstruct methods can lead to ambiguity errors and misleading results.

C# language specification

For more information, see the deconstruction section of the C# Standard.

See also