Null 合并分配

注意

This article is a feature specification. 此规范是功能的设计文档。 它包括建议的规范变更,以及功能设计和开发过程中所需的信息。 这些文章将持续发布,直至建议的规范变更最终确定并纳入当前的 ECMA 规范。

功能规范与已完成的实现之间可能存在一些差异。 Those differences are captured in the pertinent language design meeting (LDM) notes associated with .

可以在有关规范的文章中了解更多有关将功能规范子块纳入 C# 语言标准的过程。

支持者问题:https://github.com/dotnet/csharplang/issues/34

总结

将一种常见的编码模式简化,其中当变量为 null 时,为其赋予一个值。

作为该建议的一部分,我们还将放宽对 ?? 上的类型要求,允许在左侧使用类型为无约束类型参数的表达式。

动机

通常可以看到表单的代码

if (variable == null)
{
    variable = expression;
}

此建议在语言中增加了一个不可重载的二进制运算符来实现这一功能。

There have been at least eight separate community requests for this feature.

详细设计

我们添加了一种新的赋值运算符形式

assignment_operator
    : '??='
    ;

它遵循复合赋值运算符的现有语义规则(§12.21.4),但如果左侧不为空值,则省略赋值操作。 此功能的规则如下。

给定 a ??= b,其中 Aa 的类型,Bb 的类型,A0A 的底层类型(如果 A 是可为 null 的值类型):

  1. 如果 A 不存在或为不可为 null 的值类型,则会出现编译时错误。
  2. 如果 B 不能隐式转换为 AA0(如果存在 A0),则会出现编译时错误。
  3. 如果 A0 存在,并且 B 可以隐式转换为 A0,并且 B 不是动态的,那么 a ??= b 的类型就是 A0a ??= b 在运行时被评估为:
    var tmp = a.GetValueOrDefault();
    if (!a.HasValue) { tmp = b; a = tmp; }
    tmp
    
    Except that a is only evaluated once.
  4. 否则,a ??= b 的类型是 Aa ??= b 在运行时被计算为 a ?? (a = b),而 a 仅被求值一次。

为了放宽 ??的类型要求,我们更新了规范,其中当前指出,给定 a ?? b,则 Aa的类型:

  1. 如果 A 存在且不是可为 null 的类型或引用类型,则会出现编译时错误。

We relax this requirement to:

  1. 如果 A 存在,并且是不可为 null 的值类型,则会出现编译时错误。

这使得 null 合并运算符可以在无约束类型参数上工作,因为无约束类型参数 T 是存在的,不是可为 null 的类型,也不是引用类型。

缺点

与任何语言功能一样,我们必须考虑语言的额外复杂性是否能在使所有受益于该功能的 C# 程序更加清晰中得到回报。

替代方案

程序员可以手动编写 (x = x ?? y)if (x == null) x = y;x ?? (x = y)

未解决的问题

  • [ ] 我们是否还应该支持 &&=||= 运算符?

设计会议

无。