????= 运算符 - null 合并运算符

null 合并运算符 ?? 返回其左侧作数的值(如果不是 null)。 否则,它将计算右操作数并返回其结果。 如果左侧操作数的计算结果为非 null,则 ?? 运算符不会计算其右侧操作数。 仅当左操作数的计算结果为 ??= 时,Null 合并赋值运算符 null 才会将其右操作数的值赋值给其左操作数。 如果左侧操作数的计算结果为非 null,则 ??= 运算符不会计算其右侧操作数。

List<int>? numbers = null;
int? a = null;

Console.WriteLine((numbers is null)); // expected: true
// if numbers is null, initialize it. Then, add 5 to numbers
(numbers ??= new List<int>()).Add(5);
Console.WriteLine(string.Join(" ", numbers));  // output: 5
Console.WriteLine((numbers is null)); // expected: false        


Console.WriteLine((a is null)); // expected: true
Console.WriteLine((a ?? 3)); // expected: 3 since a is still null 
// if a is null then assign 0 to a and add a to the list
numbers.Add(a ??= 0);
Console.WriteLine((a is null)); // expected: false        
Console.WriteLine(string.Join(" ", numbers));  // output: 5 0
Console.WriteLine(a);  // output: 0

运算符的 ??= 左侧作数必须是变量、 属性索引器 元素。

C# 语言参考记录了 C# 语言的最新发布版本。 它还包含即将发布的语言版本公共预览版中功能的初始文档。

本文档标识了在语言的最后三个版本或当前公共预览版中首次引入的任何功能。

小窍门

若要查找 C# 中首次引入功能时,请参阅 有关 C# 语言版本历史记录的文章。

????= 运算符的左操作数的类型必须是可以为 null 的值类型。 具体而言,可以将 null 合并运算符与不受约束的类型参数一起使用:

private static void Display<T>(T a, T backup)
{
    Console.WriteLine(a ?? backup);
}

null 合并运算符是右结合运算符。 也就是说,是窗体的表达式

a ?? b ?? c
d ??= e ??= f

会像这样求值

a ?? (b ?? c)
d ??= (e ??= f)

例子

在以下方案中,和????=运算符非常有用:

  • 在使用 null 条件运算符 ?. 的表达式中 ?[],使用 ?? 运算符提供替代表达式,以计算表达式的结果是否为 null 条件运算 null

    double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
    {
        return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
    }
    
    var sum = SumNumbers(null, 0);
    Console.WriteLine(sum);  // output: NaN
    
  • 使用 可为 null 的值类型 并且需要提供基础值类型的值时,请使用 ?? 运算符指定在可以为 null 的类型值为时提供的值 null

    int? a = null;
    int b = a ?? -1;
    Console.WriteLine(b);  // output: -1
    

    Nullable<T>.GetValueOrDefault()如果当可为 null 的类型值应为基础值类型的默认值时要使用的值null,请使用该方法。

  • 若要使参数检查代码更加简洁,请使用 throw 表达式 作为运算符的 ?? 右侧作数:

    public string Name
    {
        get => name;
        set => name = value ?? throw new ArgumentNullException(nameof(value), "Name cannot be null");
    }
    

    前面的示例还演示如何使用表达式主体成员定义属性。

  • 使用 ??= 运算符替换以下格式的代码:

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

    使用以下代码:

    variable ??= expression;
    

运算符可重载性

不能重载 ????= 运算符。

C# 语言规范

有关运算符的详细信息??,请参阅 C# 语言规范Null 合并运算符部分。

有关运算符的详细信息 ??= ,请参阅 C# 语言规范的 复合赋值 部分。

另请参阅