What Is the Null-Conditional Operator in C#?
The null-conditional operator in C# provides a concise, thread-safe
way to access members and elements of an object only when that object is
not null. Introduced in C# 6.0, it prevents the common
NullReferenceException by automatically checking for null
values before proceeding with member access or method invocation. This
article explains the purpose of the null-conditional operator, how its
syntax works for member and index access, and how it simplifies
conditional logic when combined with related operators.
The Purpose of the Operator
In software development, dereferencing a variable that holds a
null reference results in a runtime crash via a
NullReferenceException. Traditionally, developers had to
write verbose defensive code using nested if statements to
ensure each reference in an object hierarchy was valid before accessing
its properties.
The null-conditional operator (?. and ?[])
was designed to eliminate boilerplate null checks. Its primary purpose
is to short-circuit operations: if the operand evaluates to
null, the entire expression returns null
immediately without throwing an exception or evaluating the rest of the
chain.
Syntax and Core Variants
C# provides two forms of the null-conditional operator:
Member Access (
?.): Used to access properties, fields, or methods.string? city = customer?.Address?.City;If
customerisnull, evaluation stops, andcityis assignednull. Ifcustomeris valid butAddressisnull, evaluation stops there. The runtime only attempts to readCityif both preceding objects are instantiated.Element Access (
?[]): Used to access indexers, collections, or arrays.int? firstScore = scores?[0];If the
scorescollection isnull, the expression evaluates tonullinstead of throwing an exception.
Short-Circuit Evaluation
The null-conditional operator relies on short-circuit evaluation. If
the left-hand side of ?. resolves to null, no
subsequent member accesses or method calls in that chain are
executed.
int? length = user?.GetProfile()?.DisplayName?.Length;In this example, if user is null,
GetProfile() is never invoked, avoiding unnecessary
processing and preventing exceptions.
Thread-Safe Event Invocation
A critical use case for the null-conditional operator is triggering events. Previously, raising an event required assigning it to a temporary variable to prevent race conditions where a subscriber might unsubscribe between the null check and the invocation:
// Traditional approach
var handler = OrderCompleted;
if (handler != null)
{
handler(this, EventArgs.Empty);
}With the null-conditional operator, this pattern is reduced to a single thread-safe line:
OrderCompleted?.Invoke(this, EventArgs.Empty);The left operand is evaluated only once, eliminating the race condition.
Pairing with the Null-Coalescing Operator
Because expressions using ?. return a nullable type
(such as int? instead of int), they are
frequently paired with the null-coalescing operator (??) to
supply a fallback default value when a null reference is
encountered.
// Returns the string length if valid, or 0 if user or Name is null
int nameLength = user?.Name?.Length ?? 0;By substituting bulky conditional blocks with expressive inline operators, the null-conditional operator minimizes boilerplate code, improves readability, and makes C# applications significantly more resilient against null-pointer errors.