Nullable reference typesThe ? and the compiler's null tracking
No narration yet
Module 4 · Lesson 112 min

The ? and the compiler's null tracking

Fusion sets <Nullable>enable</Nullable> on every project, which turns C# into a world you already know from strictNullChecks. A reference type is non-nullable by default; string cannot be null and the compiler will warn (and here, because warnings are errors, fail the build) if you might assign null to it. To allow null you write string?, exactly like TS string | null.

Nullable annotations, TS on the right in your head
public string FlightNumber { get; set; } = "";   // never null; note the initializer
public string? DecidedByName { get; set; }        // may be null (string | null)
public DateTime? DecidedAtUtc { get; set; }        // nullable value type (Date | null)

The idiomatic null check is is null and is not null, not == null. They read cleanly and can't be fooled by an overloaded == operator. You'll see them everywhere in the real code: if (row is null) return null; and x.DecidedAtUtc is not null.

Real null handling from the aggregate repository
var row = await _dbContext.FlightDisruptionCostCalcs
    .AsNoTracking()
    .Where(x => x.Id == snapshotId)
    .FirstOrDefaultAsync();

if (row is null)
{
    return null;   // flow analysis: below here, row is non-null
}

return new FlightSnapshotSummary(row.Id, row.FlightNumber, /* ... */);
Practice

Try it yourself

Do

Trace the compiler's null flow

Confirm the compiler narrows null exactly like TS does.

Tick every step to confirm you did it.