Nullable reference types
Nullable reference types (NRTs, C# 8.0+) address the common problem of NullReferenceException by changing the default behavior of reference types. When NRTs are enabled, reference types are non-nullable by default. To show that a reference type can be null, you annotate it explicitly with ?. The compiler does static flow analysis, and warns if a non-nullable type might be assigned null, or if a nullable type is dereferenced without a null check.
Configuration
NRTs are enabled project-wide with <Nullable>enable</Nullable> in the .csproj file. The different nullable contexts (enable, disable, warnings and annotations) give different levels of compiler checks and enforcement.
Syntax
Line 1 is non-nullable and line 2 is nullable. Lines 3 and 4 each produce a compiler warning. Line 5 uses the null-forgiving operator.
string nonNullableName = "Alice"; // Cannot be null without a warningstring? nullableDescription = null; // Can be nullnonNullableName = null; // Compiler warning CS8625Console.WriteLine(nullableDescription.Length); // Compiler warning CS8602 (dereference of a possibly null reference)Console.WriteLine(nullableDescription!.Length); // Null-forgiving operator: suppresses the warning if the developer is sure it's not null.Benefits
NRTs improve code safety by catching many potential null-related bugs at compile time. They make the intent about nullability clear in API contracts and variable declarations.
Attributes for API annotation
C# provides attributesAttributes and reflectionAttributes tag code with metadata, and reflection reads that metadata back at runtime.Opens in a new tab like [AllowNull], [DisallowNull], [MaybeNull], [NotNull], [MaybeNullWhen(bool returnValue)], [NotNullWhen(bool returnValue)] and [NotNullIfNotNull(string parameterName)]. They help the compiler’s static flow analysis understand the nullability semantics of APIs, especially for interop with older code, or in complex scenarios. The compiler reads these attributes at compile time, during its static flow analysis. They have no runtime role.
A cultural shift
Adopting NRTs is more than a syntax change. It requires a shift in how developers approach nulls, and it encourages more careful consideration of nullability throughout the codebase. Migrating an existing codebase can be a significant effort, but it yields substantial benefits in reducing runtime null reference exceptions.
Sources
- Nullable reference types, C#, Microsoft Learn · accessed May 16, 2025