C#idiomatic C#
null-coalescing-operatorcsharp/language-reference/operators

Language

`??` and `??=` operators - the null-coalescing operators

The `??` and `??=` operators are the C# null-coalescing operators. They return the value of the left-hand operand if it isn't null. Otherwise, they return the value of the right-hand operand

  • page csharp/language-reference/operators/null-coalescing-operator
  • updated 01/20/2026

The null-coalescing operator ?? returns the value of its left-hand operand if it's not null. Otherwise, it evaluates the right-hand operand and returns its result. The ?? operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null. The null-coalescing assignment operator ??= assigns the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null. The ??= operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null.

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/NullCoalescingOperator.csAssignment

csharp
using System.Diagnostics.CodeAnalysis;

namespace operators;

public static class NullCoalescingOperator
{
    public static void Examples()
    {
        WithNullConditional();
        WithNullableTypes();
        NullCoalescingAssignment();
    }

    public record class Human(string FirstName, string LastName)
    {
        public string FirstName { get; set; } = FirstName;
    }
    public static void AddMessageAtIndex()
    {
        List<string> messages = new List<string>(10);
        Human person = new Human("First", "Last");
        // <NullForgivingAssignment>
        person?.FirstName = "Scott";
        messages?[5] = "five";
        // </NullForgivingAssignment>

        int index = 0;
        int[] values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        // <ConditionalRHS>
        values?[2] = GenerateNextIndex();
        int GenerateNextIndex() => index++;
        // </ConditionalRHS>

        // <EquivalentIfStatement>
        if (values is not null)
        {
            values[2] = GenerateNextIndex();
        }
        // </EquivalentIfStatement>
    }

    private static void WithNullConditional()
    {
        // <SnippetWithNullConditional>
        double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
        {
            return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
        }

        var sum = SumNumbers(null, 0);
        Console.WriteLine(sum);  // output: NaN
        // </SnippetWithNullConditional>
    }

    private static void WithNullableTypes()
    {
        // <SnippetWithNullableTypes>
        int? a = null;
        int b = a ?? -1;
        Console.WriteLine(b);  // output: -1
        // </SnippetWithNullableTypes>
    }

    private class Person
    {
        string name;

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

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

    private static void NullCoalescingAssignment()
    {
        // <SnippetAssignment>
        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	        
        // </SnippetAssignment>
    }
}

The left-hand operand of the ??= operator must be a variable, a property, or an indexer element.


ms.custom: "updateeachrelease"

The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release.

The documentation identifies any feature first introduced in the last three versions of the language or in current public previews.

The type of the left-hand operand of the ?? and ??= operators can't be a non-nullable value type. In particular, you can use the null-coalescing operators with unconstrained type parameters:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/NullCoalescingOperator.csUnconstrainedType

csharp
using System.Diagnostics.CodeAnalysis;

namespace operators;

public static class NullCoalescingOperator
{
    public static void Examples()
    {
        WithNullConditional();
        WithNullableTypes();
        NullCoalescingAssignment();
    }

    public record class Human(string FirstName, string LastName)
    {
        public string FirstName { get; set; } = FirstName;
    }
    public static void AddMessageAtIndex()
    {
        List<string> messages = new List<string>(10);
        Human person = new Human("First", "Last");
        // <NullForgivingAssignment>
        person?.FirstName = "Scott";
        messages?[5] = "five";
        // </NullForgivingAssignment>

        int index = 0;
        int[] values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        // <ConditionalRHS>
        values?[2] = GenerateNextIndex();
        int GenerateNextIndex() => index++;
        // </ConditionalRHS>

        // <EquivalentIfStatement>
        if (values is not null)
        {
            values[2] = GenerateNextIndex();
        }
        // </EquivalentIfStatement>
    }

    private static void WithNullConditional()
    {
        // <SnippetWithNullConditional>
        double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
        {
            return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
        }

        var sum = SumNumbers(null, 0);
        Console.WriteLine(sum);  // output: NaN
        // </SnippetWithNullConditional>
    }

    private static void WithNullableTypes()
    {
        // <SnippetWithNullableTypes>
        int? a = null;
        int b = a ?? -1;
        Console.WriteLine(b);  // output: -1
        // </SnippetWithNullableTypes>
    }

    private class Person
    {
        string name;

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

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

    private static void NullCoalescingAssignment()
    {
        // <SnippetAssignment>
        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	        
        // </SnippetAssignment>
    }
}

The null-coalescing operators are right-associative. That is, expressions of the form

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

are evaluated as

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

Examples

The ?? and ??= operators are useful in the following scenarios:

  • In expressions that use the null-conditional operators ?. and ?[], use the ?? operator to provide an alternative expression to evaluate if the result of the expression with null-conditional operations is null:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/NullCoalescingOperator.csWithNullConditional

csharp
using System.Diagnostics.CodeAnalysis;

namespace operators;

public static class NullCoalescingOperator
{
    public static void Examples()
    {
        WithNullConditional();
        WithNullableTypes();
        NullCoalescingAssignment();
    }

    public record class Human(string FirstName, string LastName)
    {
        public string FirstName { get; set; } = FirstName;
    }
    public static void AddMessageAtIndex()
    {
        List<string> messages = new List<string>(10);
        Human person = new Human("First", "Last");
        // <NullForgivingAssignment>
        person?.FirstName = "Scott";
        messages?[5] = "five";
        // </NullForgivingAssignment>

        int index = 0;
        int[] values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        // <ConditionalRHS>
        values?[2] = GenerateNextIndex();
        int GenerateNextIndex() => index++;
        // </ConditionalRHS>

        // <EquivalentIfStatement>
        if (values is not null)
        {
            values[2] = GenerateNextIndex();
        }
        // </EquivalentIfStatement>
    }

    private static void WithNullConditional()
    {
        // <SnippetWithNullConditional>
        double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
        {
            return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
        }

        var sum = SumNumbers(null, 0);
        Console.WriteLine(sum);  // output: NaN
        // </SnippetWithNullConditional>
    }

    private static void WithNullableTypes()
    {
        // <SnippetWithNullableTypes>
        int? a = null;
        int b = a ?? -1;
        Console.WriteLine(b);  // output: -1
        // </SnippetWithNullableTypes>
    }

    private class Person
    {
        string name;

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

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

    private static void NullCoalescingAssignment()
    {
        // <SnippetAssignment>
        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	        
        // </SnippetAssignment>
    }
}
  • When you work with nullable value types and need to provide a value of an underlying value type, use the ?? operator to specify the value to provide if a nullable type value is null:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/NullCoalescingOperator.csWithNullableTypes

csharp
using System.Diagnostics.CodeAnalysis;

namespace operators;

public static class NullCoalescingOperator
{
    public static void Examples()
    {
        WithNullConditional();
        WithNullableTypes();
        NullCoalescingAssignment();
    }

    public record class Human(string FirstName, string LastName)
    {
        public string FirstName { get; set; } = FirstName;
    }
    public static void AddMessageAtIndex()
    {
        List<string> messages = new List<string>(10);
        Human person = new Human("First", "Last");
        // <NullForgivingAssignment>
        person?.FirstName = "Scott";
        messages?[5] = "five";
        // </NullForgivingAssignment>

        int index = 0;
        int[] values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        // <ConditionalRHS>
        values?[2] = GenerateNextIndex();
        int GenerateNextIndex() => index++;
        // </ConditionalRHS>

        // <EquivalentIfStatement>
        if (values is not null)
        {
            values[2] = GenerateNextIndex();
        }
        // </EquivalentIfStatement>
    }

    private static void WithNullConditional()
    {
        // <SnippetWithNullConditional>
        double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
        {
            return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
        }

        var sum = SumNumbers(null, 0);
        Console.WriteLine(sum);  // output: NaN
        // </SnippetWithNullConditional>
    }

    private static void WithNullableTypes()
    {
        // <SnippetWithNullableTypes>
        int? a = null;
        int b = a ?? -1;
        Console.WriteLine(b);  // output: -1
        // </SnippetWithNullableTypes>
    }

    private class Person
    {
        string name;

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

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

    private static void NullCoalescingAssignment()
    {
        // <SnippetAssignment>
        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	        
        // </SnippetAssignment>
    }
}

Use the System.Nullable.GetValueOrDefault method if the value to use when a nullable type value is null should be the default value of the underlying value type.

  • To make the argument-checking code more concise, use a throw expression as the right-hand operand of the ?? operator:

sample · csharpdocs/csharp/language-reference/operators/snippets/shared/NullCoalescingOperator.csWithThrowExpression

csharp
using System.Diagnostics.CodeAnalysis;

namespace operators;

public static class NullCoalescingOperator
{
    public static void Examples()
    {
        WithNullConditional();
        WithNullableTypes();
        NullCoalescingAssignment();
    }

    public record class Human(string FirstName, string LastName)
    {
        public string FirstName { get; set; } = FirstName;
    }
    public static void AddMessageAtIndex()
    {
        List<string> messages = new List<string>(10);
        Human person = new Human("First", "Last");
        // <NullForgivingAssignment>
        person?.FirstName = "Scott";
        messages?[5] = "five";
        // </NullForgivingAssignment>

        int index = 0;
        int[] values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        // <ConditionalRHS>
        values?[2] = GenerateNextIndex();
        int GenerateNextIndex() => index++;
        // </ConditionalRHS>

        // <EquivalentIfStatement>
        if (values is not null)
        {
            values[2] = GenerateNextIndex();
        }
        // </EquivalentIfStatement>
    }

    private static void WithNullConditional()
    {
        // <SnippetWithNullConditional>
        double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
        {
            return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
        }

        var sum = SumNumbers(null, 0);
        Console.WriteLine(sum);  // output: NaN
        // </SnippetWithNullConditional>
    }

    private static void WithNullableTypes()
    {
        // <SnippetWithNullableTypes>
        int? a = null;
        int b = a ?? -1;
        Console.WriteLine(b);  // output: -1
        // </SnippetWithNullableTypes>
    }

    private class Person
    {
        string name;

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

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

    private static void NullCoalescingAssignment()
    {
        // <SnippetAssignment>
        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	        
        // </SnippetAssignment>
    }
}

The preceding example also demonstrates how to use expression-bodied members to define a property.

  • Use the ??= operator to replace code of the following form:

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

    Use the following code:

    csharp
    variable ??= expression;

Operator overloadability

You can't overload the ?? and ??= operators.

C# language specification

For more information about the ?? operator, see The null coalescing operator section of the C# language specification.

For more information about the ??= operator, see the Compound assignment section of the C# language specification.

See also