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.