What's New in C# 14: Null-Conditional Assignments
Semantics of null-conditional assignment
- New feature:
a?.b = c;only performs the assignment if the object to the left of?.is non-null; if it’s null, both the assignment and evaluation of the right-hand side are skipped. - This aligns with existing null-conditional behaviors (
x?.Invoke(),x?.Property,x?["key"]) where the entire trailing expression is skipped when the receiver is null. - Some commenters find this intuitive and consistent (“every
?implies control flow”), others dislike that it alters expected evaluation order and hides control flow inside an expression.
Predictability, side effects, and “mutable place” concerns
- Skipping RHS evaluation is controversial: it can silently drop side effects like
GetNextId()or logging. - One camp argues that using
?.explicitly asks for “do nothing if it’s null,” and this must include skipping side effects for consistency. - Another camp says assignments should “stick” once written; discarding a computed value or side effects feels like breaking the usual contract of assignment.
- Some propose an alternative “materialize-on-write” semantics (allocate intermediate objects instead of dropping the write), but others argue that would be even more magical and problematic.
Use cases vs. code smell
- Proponents:
- Removes verbose and bug-prone null-check boilerplate, especially when complex expressions are used multiple times.
- Makes refactoring and conditional configuration-style code more concise and less error-prone.
- Skeptics:
- If you’re often assigning deep into nullable chains, the data model may be wrong; this feature makes it easier to paper over that.
- Fear that developers will add
?to silence null exceptions without thinking through the correct behavior.
Readability, overuse, and style
- Concerns about “question mark fatigue”: with
?.,??,?[],??=and nullable types, null-handling syntax can overwhelm code. - Some reviewers say they would flag assignment forms as too subtle, preferring explicit
ifblocks for clarity. - Others argue it actually reduces mental load by unifying patterns and avoiding duplicated expressions, and teams can always disallow it via analyzers or language-version settings.
Broader language and ecosystem context
- Part of an ongoing push to make null-handling safer and more expressive; some feel C# is becoming complex like C++, others see these as small, consistent extensions.
- Similar constructs exist in Swift, Kotlin, Groovy, Ruby, TypeScript, etc., where they generally haven’t caused major problems.
- Side discussion touches on long-awaited discriminated unions (still in active design), C#’s growing feature set, and .NET’s perceived maturity versus trendiness.