这个C#语法叫什么名字(多元组样式赋值)?

4

我在微软文档中找到了这个语法:

public NewsStoryViewModel(DateTimeOffset published, string title, string uri) =>
        (Published, Title, Uri) = (published, title, uri);

它可以在一条语句中进行多重赋值,但我不太确定它叫什么或者它是如何工作的。

这是通过假装这些是元组来进行多重赋值的一种技巧吗?还是它有自己的名字?

P.S. 如果有人感兴趣,可以在这里找到相关信息。

P.P.S. 我想知道的不是缺少 {},而是第2行使用了“高级”赋值而不是传统赋值。


3
实际上,这些是元组,在 C# 7 中已被完全支持。 - Alejandro
3
这是一个表达式主体方法(带有3个参数),而不是元组。它看起来也是一个构造函数... 它正在初始化 ViewModel 的3个属性。 - Ron Beyer
2
https://csharp.today/c-7-deconstruction/ - adt
@adt 我也这么想,但我并没有任何“解构”方法,然而这段代码确实可以编译。 - Ilya Chernomordik
@RonBeyer,我没有表达得够清楚,已经稍微编辑了一下问题,我想知道的不是表达式主体方法,而是另一行代码。 - Ilya Chernomordik
3个回答

10

这真是令人困惑的语法,因为左右两边看起来都一样,但左边是解构语法,而右边是元组声明。但感谢您的答案,这澄清了事情! - Ilya Chernomordik

5

我不知道他们是否有针对构造函数特别称呼这种操作的官方术语,但作为一般模式,它被称为解构。只要赋值的右侧具有适当的Deconstruct方法,您就可以像这样批量提取类型中的值并执行赋值操作。对于元组,可以这样做:

var (x, y, z) = (1, 2, 3);

在道德上等同于

var tuple = (1, 2, 3);
var x = tuple.Item1;
var y = tuple.Item2;
var z = tuple.Item3;

左侧可以有任何可分配变量,它们可以是构造函数中的本地变量、字段或只读属性。使用它是个人偏好和代码风格,我通常按照MSDN文档的方式使用它们——将基本构造函数写在一行中。
class C
{
    private int Prop1 { get; }
    private D Prop2 { get; }
    private string Prop3 { get; }

    public C(int prop1, D prop2, string prop3) =>
        (Prop1, Prop2, Prop3) = (prop1, prop2, prop3);
}

有趣的是,Roslyn编译器能够识别这种模式并避免实际创建元组。如果你将其输入反编译器,你会发现生成的代码与以下代码相同:
public C(int prop1, D prop2, string prop3)
{
    Prop1 = prop1;
    Prop2 = prop2;
    Prop3 = prop3;
}

我不知道这是否有记录,但要感谢Jon Skeet在他的《C#深度剖析》(第4版)中提到了这一点。
更新: 出于好奇,我检查了一下是否还可以在其他地方应用此优化。似乎只要左侧变量是refout参数就可以。例如:
public void Deconstruct(out int prop1, out object prop2, out string prop3) =>
    (prop1, prop2, prop3) = (_prop1, _prop2, _prop3);

生成等效于此代码的代码:
public void Deconstruct(out int prop1, out object prop2, out string prop3)
{
    int temp1 = _prop1;
    object temp2 = _prop2;
    string temp3 = _prop3;
    prop1 = temp1;
    prop2 = temp2;
    prop3 = temp3;
}

我猜测,由于对“普通”变量和ref变量进行赋值时中间语言不同,因此第二种情况的优化可能没有实现,但我可能是错误的。


这对Roslyn来说是很聪明的做法,我刚才还在想以这种方式编写会有一些开销 :) - Ilya Chernomordik

1
第二行基本上充当属性的 setter。在 C# 7.0 之前,可以使用以下方式:
public NewsStoryViewModel(DateTimeOffset published, string title, string uri) 
{
        Published = published;
        Title = title; 
        Uri = uri;
}

C# 7.0:
public NewsStoryViewModel(DateTimeOffset published, string title, string uri) =>
        (Published, Title, Uri) = (published, title, uri);

作为已经定义好的内容,标题和URI可以像上面那样直接赋值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接