Nullable Value Types (Nullable<T>) vs Nullable Reference Types (NRT)
1Concept
`Nullable<T>` (`int?`) is a genuine 8-byte value type struct with `bool HasValue` and `T Value`. In contrast, Nullable Reference Types (`string?`) are static Roslyn compiler annotations with zero runtime overhead.
2Architecture Diagram
Nullable<int> Layout (8 Bytes): ┌─────────────────────────┬─────────────────────────┐ │ bool HasValue (1 Byte) │ int Value (4 Bytes) │ + 3 Bytes Alignment Padding └─────────────────────────┴─────────────────────────┘ Nullable Reference Type (string?): Standard 8-Byte Pointer + Compiler Metadata Attribute ([Nullable(2)])
3Code Example
C# 13 & .NET 9
using System;
public class NullableComparisonDemo
{
public static void Main()
{
int? nullableInt = null;
Console.WriteLine($"Nullable Value Type HasValue: {nullableInt.HasValue}");
nullableInt = 42;
Console.WriteLine($"Value: {nullableInt.GetValueOrDefault(-1)}");
string? nullableString = null; // Roslyn checks at compile time
Console.WriteLine($"NRT String Length: {nullableString?.Length ?? 0}");
}
}4Expected Output
Nullable Value Type HasValue: False Value: 42 NRT String Length: 0
5Key Takeaways
- ✓`int?` adds storage size and padding overhead.
- ✓Nullable Reference Types generate no runtime memory overhead.
- ✓Use the null-forgiving operator (`!`) only when you have guaranteed invariants outside compiler visibility.