Nullable Reference Types in C#
Enable nullable reference type annotations (C# 8+), use ? on reference types, null-forgiving operator !, and the null-coalescing operators ?? and ??=.
The Null Problem
1. NullReferenceException — The Billion Dollar Mistake
Accessing a member on a null reference throws NullReferenceException.
2. Why "The Billion Dollar Mistake"
In 1965, Sir Tony Hoare introduced the null reference into ALGOL W — a language he was designing at the time. Decades later, he publicly called it his "billion dollar mistake." His reasoning: null was easy to implement, but it made every reference type in every language that adopted the idea unsafe by default. Any variable that could hold an object could silently hold nothing instead, and the only way to find out was a crash at runtime. The cost has been staggering. Null-related bugs — NullPointerException in Java, NullReferenceException in C#, segmentation faults in C/C++ — account for a huge proportion of production incidents, security vulnerabilities, and hours of debugging across the entire software industry. Estimates put the aggregate economic damage in the billions of dollars, hence the name. What makes it especially insidious is that the bug is invisible at the point of assignment. You write code that looks perfectly correct, the compiler accepts it, tests may pass, and then — in production, under the right conditions — a value that was assumed to be present turns out to be null and the application crashes or returns corrupted data. The further the null travels from where it was introduced to where it is dereferenced, the harder it becomes to trace. Modern languages have addressed this in different ways. Kotlin and Swift use non-nullable types by default, requiring explicit ? to opt into nullability. Rust eliminates null entirely with its Option<T> type. C# took a pragmatic, opt-in approach with Nullable Reference Types in C# 8 — because millions of existing codebases relied on the old behaviour, making the change mandatory would have broken them all. Instead, you enable the nullable context and the compiler adds static flow analysis to warn you about potential null dereferences before they reach production.
Enabling Nullable Context
1. #nullable enable — Per File
Add `#nullable enable` at the top of a file to opt in.
2. Project-Wide in .csproj
Enable NRT for the whole project by adding `<Nullable>enable</Nullable>` in the project file.
Nullable Reference Types ?
1. Nullable Variables and Fields
Use `string?` for values that may be null; `string` for values that must not be.
2. Nullable Parameters and Return Types
Annotate method signatures — callers and the compiler know what to expect.
Null-Safety Operators
1. Null-Conditional ?. and ?[]
`?.` short-circuits to null instead of throwing when the object is null.
2. Null-Coalescing ?? and ??=
`??` provides a fallback; `??=` assigns only when null.
Null-Forgiving Operator !
1. The ! Operator
Append `!` to suppress a nullable warning — use sparingly.
Null Guards & Patterns
1. ArgumentNullException.ThrowIfNull (.NET 6+)
One-liner null guard for method arguments — replaces manual if+throw.
2. is null and is not null Patterns
Use patterns for null checks — safer than == null when operators may be overloaded.
Nullable in Practice
1. Constructor Null Safety
Initialize non-nullable fields in the constructor or use required properties.
2. Flow Analysis — Compiler Tracks Null State
The compiler tracks null state through branches and narrows types automatically.