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.