析构表达式 - 从元组或其他用户定义的类型中提取字段的属性

析构表达式从对象的实例中提取数据字段。 每个离散数据元素将写入不同的变量,如以下示例所示:

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

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

前面的代码片段创建了一个元组,它有两个整数值 XY。 第二个语句 解构元组,并将元组元素存储在离散变量 xy中。

元组析构

所有元组类型都支持析构表达式。 元组析构提取所有元组的元素。 如果只想使用某些元组元素,请对未使用的元组成员使用弃元,如以下示例所示:

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

在前面的示例中,将丢弃 Ylabel 成员。 可以在同一解构表达式中指定多个弃元。 可以对元组的所有成员使用丢弃。 以下示例是合法的,但没有用:

var (_, _, _) = tuple2;

记录析构

具有主构造函数记录类型支持对位置参数的析构。 编译器合成 Deconstruct 方法,该方法提取从主构造函数中的位置参数合成的属性。 编译器合成的 Deconstruction 方法不会提取在记录类型中声明为属性的属性。

以下代码中显示的 record 声明两个位置属性SquareFeetAddress,以及另一个属性 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 方法,或声明为该类型的扩展方法。 析构表达式调用方法 void Deconstruct(out var p1, ..., out var pn)Deconstruct 方法可以是实例方法或扩展方法。 Deconstruct 方法中每个参数的类型必须与析构表达式中相应参数的类型匹配。 析构表达式将每个参数的值分配给 Deconstruct 方法中相应 out 参数的值。 如果多个 Deconstruct 方法与析构表达式匹配,编译器会报告歧义错误。

以下代码声明具有两个 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;
    }
}

第一种方法支持提取所有三个轴值的析构表达式:XYZ。 第二种方法仅支持析构平面值:XY。 第一种方法的 arity 为 3;第二种方法的 arity 为 2。

上一部分介绍了 Deconstruct 类型的编译器合成 record 方法,该方法带有一个主构造函数。 可以在记录类型中声明更多 Deconstruct 方法。 这些方法可以添加其他属性、删除一些默认属性或两者。 还可以声明与编译器合成签名匹配的 Deconstruct。 如果声明这样的 Deconstruct 方法,编译器不会合成一个。

只要编译器可以确定解构表达式的唯一 Deconstruct 方法,就可以允许多个 Deconstruct 方法。 通常,同一类型的多个 Deconstruct 方法具有不同数量的参数。 还可以创建多个因参数类型而异的 Deconstruct 方法。 但是,在许多情况下,过多的 Deconstruct 方法可能会导致歧义错误和误导性结果。

C# 语言规范

有关详细信息,请参阅 C# 标准的析构部分。

另请参阅