Skip to content

C# Null Conditional Operator Not Working Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about C# Null Conditional Operator Not Working Fix. We cover key concepts, practical examples, and best practices.

The Problem

You use the null-conditional operator ?. expecting safe navigation, but your code still throws a NullReferenceException or behaves unexpectedly:

var city = person?.Address?.City;
Console.WriteLine(city.ToUpper()); // NullReferenceException

The null-conditional operator short-circuits to null when any member is null, but calling a method on the result without a null check still crashes.

Quick Fix

Step 1: Always follow ?. with a null check or ??

WRONG -- calling methods on the nullable result:

string city = person?.Address?.City;
Console.WriteLine(city.ToUpper());

RIGHT -- use the null-coalescing operator ?? to provide a default:

string city = person?.Address?.City ?? "Unknown";
Console.WriteLine(city.ToUpper());

Step 2: Understand that ?. returns a nullable

WRONG -- assigning to a non-nullable type:

int length = person?.Name?.Length; // CS0266: Cannot implicitly convert int? to int

RIGHT -- use ?? to handle the nullable:

int length = person?.Name?.Length ?? 0;

Or access the nullable value explicitly:

int? length = person?.Name?.Length;

Step 3: Use ?. with method invocations

WRONG -- calling a method on a possibly-null object:

if (person != null)
{
    person.Save();
}

RIGHT -- use ?. with method invocation:

person?.Save();

The method is called only if person is not null. This works with Action and Func delegates too:

Action<string> logger = GetLogger();
logger?.Invoke("Log this message");

Step 4: Array and indexer access with ?.

WRONG -- direct indexer access on a null array:

int[] numbers = GetNumbers();
int first = numbers?[0] ?? -1;

RIGHT -- this actually works correctly, but ensure you understand that numbers?[0] returns int?:

int[] numbers = GetNumbers();
int first = numbers?[0] ?? -1;

Step 5: Avoid overuse in event handlers

WRONG -- verbose event invocation pattern:

var handler = OnDataReceived;
if (handler != null)
{
    handler(this, EventArgs.Empty);
}

RIGHT -- concise null-conditional invocation:

OnDataReceived?.Invoke(this, EventArgs.Empty);

This is thread-safe because the runtime evaluates ?.Invoke atomically.

Step 6: Beware of value type null propagation

WRONG -- expecting ?. on non-nullable value types to compile:

int value = GetValue();
int? result = value?.ToString(); // value is not nullable

RIGHT -- box to nullable first or use a different approach:

int value = GetValue();
string result = value.ToString();

The ?. operator only works on nullable value types and reference types.

Prevention

  • Always pair ?. with ?? when the result feeds into further operations.
  • Remember that ?. returns a nullable type for value types.
  • Use ?.Invoke for event raising to avoid thread-safety issues.
  • Do not use ?. with non-nullable value types.
  • Test both null and non-null paths when using ?. in LINQ queries.

Common Mistakes with null conditional

  1. Using foldl instead of foldl' causing stack overflow on large lists
  2. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  3. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable

These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why does `person?.Name.ToUpper()` still throw?

The ?. only applies to the immediate member access. person?.Name.ToUpper() is parsed as (person?.Name).ToUpper(). If person is null, the whole expression is null. But if person is not null and Name is null, .ToUpper() throws. Use person?.Name?.ToUpper() for full null propagation.

Is ?. thread-safe for events?

Yes. The ?.Invoke pattern is thread-safe because the runtime evaluates the delegate, checks for null, and invokes in a single atomic operation. The old pattern of copying to a local variable is no longer necessary.

Can I use ?. with custom operators?

No. The ?. operator is built into the language and cannot be overloaded. It works on any reference type or nullable value type regardless of custom operators defined on the type.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro