NullReferenceException is the classic .NET crash; the compiler's null analysis prevents most of them.
Value types like int can never be null; int? (short for Nullable<int>) adds a null state, with HasValue and Value, or GetValueOrDefault().
Reference types (classes, strings, arrays) can be null at runtime. With nullable reference types enabled (<Nullable>enable</Nullable>, the default in new projects), the compiler tracks nullability:
stringmeans "should never be null"; assigningnullgives a warning.string?means "may be null"; dereferencing it without a check gives a warning.
The compiler does flow analysis: after if (name is null) return; it knows name is non-null. These are warnings, not runtime checks, so treat them seriously (or enable warnings as errors).
Operators for working with null:
a?.Breturns null instead of throwing ifais null;a?[0]for indexers.x ?? fallbackuses the fallback whenxis null;x ??= valueassigns only if null.x is null/x is not nullare the clearest checks (they can't be overloaded).x!(null-forgiving) tells the compiler "trust me"; overuse defeats the feature.
ArgumentNullException.ThrowIfNull(arg) validates public method arguments. C# 14 also allows null-conditional assignment: customer?.Order = order; only assigns when customer is non-null.
Example
int? maybeAge = null;
Console.WriteLine(maybeAge.HasValue); // False
Console.WriteLine(maybeAge ?? -1); // -1
string? FindUser(int id) => id == 1 ? "Ada" : null;
string? user = FindUser(2);
Console.WriteLine(user?.Length); // (empty line: null)
Console.WriteLine(user?.Length ?? 0); // 0
user ??= "guest";
Console.WriteLine(user.ToUpper()); // GUEST
static int Len(string? s)
{
if (s is null) return 0;
return s.Length; // compiler knows s is not null here
}
Console.WriteLine(Len(FindUser(1))); // 3Remember
- int? adds null to value types
- With nullable reference types on, string? may be null and string should not be
- ?. and ?? replace most manual null checks
- Use the ! operator rarely; fix the flow instead
Watch out for
- Silencing every warning with ! instead of handling the null case.