Browse C# 14

C# 14: Null-Conditional Assignment Operator

C# 14 lets you use ?. or ?[] on the left side of an assignment, so the right side never evaluates when the object is null. Here's why that matters.

There's also a video on this topic using different examples, and the two complement each other.

C# 14 introduces null-conditional assignment: the ability to use ?. or ?[] on the left side of an assignment operator so the right-hand side is never evaluated when the object is null. It’s a small syntax addition, but it eliminates a real class of bugs involving wasted work.

The problem

Take a nullable object with a property you want to populate from an expensive operation:

WorldSimulation? sim = null;

sim.Map = GenerateRandomMap(); // NullReferenceException

Running this throws a NullReferenceException - but only after GenerateRandomMap() finishes. That’s because the assignment operator is right-to-left associative: the right side is evaluated first, so the map generation runs first to completion, after which the runtime discovers that sim is actually null and crashes.

This wastes both time and resources.

The existing fix

The standard solution is an explicit null check:

WorldSimulation? sim = null;

if (sim is not null)
{
    sim.Map = GenerateRandomMap();
}

This works. The null check essentially guards the entire block, so GenerateRandomMap() never runs when sim is null. But it takes multiples lines just for a single assignment.

The C# 14 fix

As mentioned above, starting in C# 14 (.NET 10) you can use null-conditional member access operator (?.) or null-conditional element access operator ?[] on the left side of an assignment or compound assignment operator.

Below is an example of null-conditional member access operator:

WorldSimulation? sim = null;
sim?.Map = GenerateRandomMap(); // GenerateRandomMap() never runs

WorldSimulation sim = new();
sim?.Map = GenerateRandomMap(); // GenerateRandomMap() runs, result is assigned

When the left side contains a null-conditional operator, the evaluation order is reversed. The left side is evaluated first to check whether any part of the access chain is null. If it is null, the entire assignment is skipped and the right side is never evaluated. If it is not null, the right side runs and the assignment proceeds normally.

And now below is an example of null-conditional element access operator on the left side - for example, if newMaps is a nullable array, the right side is skipped when newMaps is null, but proceeds normally otherwise:

Map[]? newMaps = null;
newMaps?[0] = GenerateRandomMap(); // GenerateRandomMap() never runs

newMaps = new Map[5];
newMaps?[0] = GenerateRandomMap(); // GenerateRandomMap() runs, result is assigned

The takeaway

The right side of an assignment can be expensive. Database queries, HTTP calls, file I/O and other expensive operations - anything that takes real time or allocates real resources. Skipping that work when the target is null is the right default behavior, and ?. along with ?[] now make it easier than ever.

The null-conditional assignment doesn’t change what’s possible - you could always write the if block - but it makes the correct behavior easier to express and easier to read.

Related reading

  • .NET

    Modern .NET Explained: A Beginner-Friendly Guide Video

    What .NET actually is, how it evolved from .NET Framework to a unified modern platform, and what you need to know to get started without any confusion.

    5 min
  • C#

    C# Tuples: Group Values Without Creating a Type Video

    Tuples let you return multiple values from a method without a custom class or out parameters. Here's the syntax, when to use them, and the difference between Tuple and ValueTuple.

    4 min
  • C# 15

    C# 15: Collection Expression Arguments Video

    C# 15 extends collection expressions with the with keyword, letting you pass constructor arguments like capacity or a comparer directly inside the expression.

    2 min