If I had a nickel for every time I saw int? treated like string?, I could probably fund my coffee habit. Nullable value types look friendly, but under the hood they have their own rules. Treat them like references and they will absolutely prank you in production. Let's take a few minutes to demystify Nullable<T> with a tour of how it is represented at runtime, what happens during boxing, how operator lifting works, and the common traps that bite even experienced C# devs.

The real shape of Nullable

T? is syntax sugar for System.Nullable<T>, which is a struct with two fields in spirit: a bool HasValue and a T Value. It preserves value semantics while adding an explicit notion of absence.

Before we do anything fancy, let us get our footing.

int? hp = null;
Console.WriteLine(hp.HasValue);       // False
Console.WriteLine(hp.GetValueOrDefault()); // 0

int? shields = 100;
Console.WriteLine(shields.HasValue);  // True
Console.WriteLine(shields.Value);        // 100

Reading .Value when HasValue is false throws InvalidOperationException, not NullReferenceException. That difference matters when you are debugging.

int? mana = null;
// Console.WriteLine(mana.Value);   // Would throw InvalidOperationException
Console.WriteLine(mana ?? 50);       // Use a safe fallback

This article will be available on March 16, 2026 at 8 AM Central Time US