Nullable Value Types and the Null-State Machine
int? vs int, HasValue/GetValueOrDefault, nullable reference type annotations, and making the compiler's warnings into design.
Nullable value types: absence you can see
A value type cannot be null โ unless you wrap it: int? is
Nullable<int>, a struct holding a bool HasValue plus a T Value.
int? found = list.Find(x => x > 10); // 0 would be a lie; null means "none"
if (found is int value) Use(value); // pattern test + unwrap in one step
int fallback = found ?? -1; // GetValueOrDefault-style default
int? lifts operators: null + 5 is null (not an exception). Comparisons
with null are false โ null < 5 is false, not true.
Nullable reference types: promises the compiler checks
Since C# 8, reference types are non-nullable by default under NRT. The compiler tracks null-state and warns:
string?โ "may be null"; you must check before use.stringโ "expected non-null"; assigning null warns.string? name = Fetch(); var len = name.Length;โ warning: possible null.- After
if (name != null)the compiler knows it is safe โ flow analysis. !(null-forgiving) says "trust me" โ a last resort, not a tool.
Two honest tools when null is a legitimate answer:
string? found = dict.GetValueOrDefault(key); // null is real absence
string found2 = dict.GetValueOrDefault(key, ""); // or a default
And one dishonest one to avoid: initializing fields with = null! to
silence the compiler creates a lie that explodes later.
The nullable machinery in API design
TryX patterns (like Beginner's int.TryParse) return bool + out value;
nullable returns let you express "no result" directly:
public static int? ParseAge(string input) =>
int.TryParse(input, out int age) && age >= 0 ? age : null;
Callers then use ??, is int v, or if (v is not null) โ null becomes a
visible, checkable part of the contract instead of an ambush.
Check your understanding
- What is
(int?)null == null? (True โ lifted equality.) string s = null;under NRT โ warning or error? (Warning; still compiles.)- Why prefer
int?over a magic-1sentinel? (Sentinels collide with real data.)