The C# coalesce operator (??) returns the left operand when it is non-null, or the right operand when the left is null, enabling concise null-coalescing and fallback defaults in expressions. The compound assignment form ??= assigns the right operand only when the left is null, streamlining initialization. This guide explains how these operators work, when to prefer them, performance considerations, and idioms that keep code predictable and safe.
How the Coalesce Operator Works
The null-coalescing operator ?? evaluates a nullable or nullable reference type expression and returns the left value if it is not null; otherwise, it returns the right operand. It requires the left and right sides to be compatible types or with defined implicit conversions, and the result type follows the nullable context and type inference rules of the surrounding expression. Unlike the conditional ternary, ?? is specifically designed for null checks and tends to read clearly for fallback assignments.
Syntax and Basic Examples
Use the ?? operator to provide a default when a variable, property, or query result might be null. The expression a ?? b yields a when a is non-null; otherwise, it yields b. Common scenarios include providing defaults for strings, numbers, or reference types and simplifying parameter validation patterns.
Compound Coalesce Assignment: ??=
The ??= operator performs compound assignment only when the left-hand variable is null, combining a null check and assignment into one line. It is particularly useful for lazy initialization of fields or properties, reducing boilerplate while making the null-coalescing intent explicit. Because it assigns only on null, repeated calls avoid overwriting existing values.
Differences Between ?? and ??=
- ?? is an expression that returns a value based on nullness without modifying its operands.
- ??= is a statement that conditionally assigns to its left-hand variable when that variable is null.
- Use ?? when you need a fallback value in an expression; use ??= when you want to initialize once if currently null.
Practical Usage Patterns
Apply the coalesce operator to simplify null handling in constructors, method bodies, and object initializers, while ensuring that defaults are explicit and consistent. Prefer ?? for safe fallbacks in return statements and query projections; prefer ??= for one-time initialization of fields and cached values. Combine with argument null checks or Guard Clauses when public APIs require clear failure semantics instead of silent defaults.
Common Idioms
- string name = input ?? "unknown";
- items ??= new List<Item>();
- return repository.Get(id) ?? CreateDefault(id);
Performance and Side Effects
The ?? operator evaluates the left operand once and, only if it is null, evaluates the right operand. Be cautious when the right operand involves method calls or property accesses that carry side effects or cost, because those evaluations are deferred until needed. With ??= the right side is evaluated only on null assignment, which helps avoid unnecessary work while still protecting against repeated initialization overhead.
Performance Considerations at a Glance
| Aspect | Verified Detail | Source Type |
|---|---|---|
| Evaluation Strategy | Left operand always evaluated; right operand only if left is null | Language Specification |
| ??= Assignment Cost | Conditional assignment occurs only on null, avoiding redundant writes | Implementation Behavior |
| Side-effect Timing | Right side of ?? and ??= is not evaluated until needed | Language Specification |
| Readability vs Ternary | ?? is clearer for null-coalescing; ternary handles non-null conditions | Best Practices |
Common Pitfalls and Misuses
Avoid using ?? when null has meaningful semantic value and a sentinel or explicit check is required. Be cautious with nullable value types where default(T) may be a valid non-null state, and ensure that the fallback value does not mask configuration or data errors. With nullable reference types, enable context annotations and warnings to distinguish between deliberate defaults and unintended null propagation.
Guidelines to Follow
- Prefer explicit null checks when the contract requires distinguishing null from other invalid states.
- Use ??= for lazy initialization of collections, caches, and expensive-to-create objects.
- Keep the right operand side free of side effects or expensive computation when possible.
- Combine with nullable annotations and static analysis to make null intent explicit across the codebase.
Interop with Other Language Features
The coalesce operator works naturally with nullable reference types, pattern matching, and ternary expressions, allowing you to write expressive conditional logic while preserving readability. In combination with pattern matching, you can first test for null and then apply fallbacks, or integrate with conditional expressions when more complex logic is required. Be mindful when mixing with async methods, as the right operand should not introduce blocking unless the surrounding context already supports asynchronicity.
Comparison with Similar Constructs
| Feature | Null-Coalescing (??) | Conditional (?:) | Null-Coalescing Assignment (??=) |
|---|---|---|---|
| Purpose | Fallback on null | General conditional selection | Conditional assignment on null |
| Operands | Two, both evaluated with left-first | Three, all evaluated unless short-circuited | Two, right evaluated only when left is null |
| Side-effect Safety | Deferred right evaluation | All branches evaluated before selection | Assignment only when needed |