?? と ??= 演算子 - 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	        

??= 演算子の左側のオペランドは、変数、プロパティ、またはインデクサー要素である必要があります。

?? および ??= 演算子の左側のオペランドの型は、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
    

    null 値許容型が null の場合に使用される値を、基になる値型の既定値にする場合は、Nullable<T>.GetValueOrDefault() メソッドを使用します。

  • ?? 演算子の右側のオペランドとして 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 合体演算子に関するセクションを参照してください。

??= リテラルの詳細については、機能提案メモを参照してください。

参照