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 if blocks 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.