Every way to handle null
string?, is null, ?., ??, ??=, the ! operator, int? and returning null on purpose. What each one says about a missing value, and which to reach for.
Start with one question: is "missing" a real answer here, or a bug?
- It should never be missing (a customer's name, a required
setting) → keep the type non-nullable (
string) and make sure it gets a value: a constructor,required, or a starting value. If a caller can still passnullagainst the warnings, a guard clause at the top of the method stops it there. - Missing is normal and has a sensible default (no nickname,
use the first name) →
??, or?.followed by??:user.Nickname ?? user.FirstName,order?.Customer?.Email ?? "(none)". - Missing needs its own behaviour (no account for that email) →
test it:
if (found is null) { ... return; }, orif (input is string text)to test and name it in one go. - A number, date or bool that might be absent (a form's
optional age, a rating nobody gave yet) →
int?,DateOnly?,bool?, read with??,HasValueoris int n. - You're writing a lookup that can fail → return
T?so every caller's compiler warns them to check. If callers need to know why it failed, a Try method or a result object says more (see "Every way to handle failure"). - The compiler is wrong and you can prove it →
!, last, with the reason written beside it. A!that's wrong is a crash waiting to happen.
A nullable warning is the compiler asking you which of these cases you meant. Answer it; don't silence it.
Where null comes from
Section
ReadLine returns string?
The first null you meet. Console.ReadLine gives back null when input runs out, and ?? fills in a default.
Section
null, a reference to nothing
A reference-type variable can point at no object at all, and using one crashes with NullReferenceException.
How nulls sneak in, and how string versus string? turns a run-time crash into a compile-time warning.
Saying whether null is allowed
Section
Annotations and warnings
T? means "might be null", plain T means "never". Includes CS8618 for properties no constructor sets.
Nullable
A required property must be set when the object is created, so it can stay non-nullable.
Working with a value that might be null
Section
?., ?[], ??, ??= and ?.=
Read through a null, fill in a default, assign only when empty, or write through a maybe-null reference (C# 14).
x is null and x is not null are constant patterns; is string s tests and names in one step.
Formal. With nullable reference types enabled, the compiler tracks
each reference as not-null or maybe-null along every code path. It
warns when a maybe-null value is dereferenced (CS8602), or stored or
passed where a non-nullable type is expected (CS8600, CS8601, CS8604,
CS8625). A null check (is not null, != null, a type pattern, an
early return) moves the variable's state to not-null, and so does
x ??= value; an expression like x ?? "default" produces a not-null
value but leaves x itself maybe-null. The null-forgiving !
changes the state to not-null for the compiler only; it emits no
run-time check. The analysis produces warnings, never different
generated code.
In plain English. The compiler reads your code like a careful
reviewer and flags every place a missing value could crash. Checking for
null satisfies it. Writing ! only tells the reviewer to stop
complaining; it doesn't make the value exist.
Example. string? name = Find(); Console.WriteLine(name.Length);
warns CS8602; if (name is not null) Console.WriteLine(name.Length);
does not.
Why this rule exists. Null dereferences were among the most common run-time crashes; catching them while you type is far cheaper than in production.
How the compiler decides whether a variable is maybe-null at each line, and what makes it change its mind.
When the compiler lacks information you have. ! silences the warning; it doesn't check anything.
Returning null on purpose
When returning null is the honest answer, and when a Try method or result object says more.
Section
FirstOrDefault and friends
The OrDefault forms return default(T), which is null for reference types, instead of throwing when nothing matches.
Fixing a warning the right way
Section
Every warning has a right fix
The five questions to ask, in order, and a table from CS8600 to CS8629 with the usual fix for each.