C# Nullable Types
In C#, value types like int, double, and bool always hold a value — they can never be empty. But in real programs, data is sometimes missing or unknown. Nullable types let value types hold an empty (null) state as well.
The Problem: Missing Data
Imagine a form where age is optional. An int can hold 0, but 0 could also be a valid age (for a newborn). You need a way to say "age was not provided at all." That is where nullable types help.
┌─────────────────────────────────────────────────────────────┐ │ NULLABLE TYPE CONCEPT │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Regular int: │ │ ┌────────────────────────────────────────┐ │ │ │ Must always hold a number: 0, 1, -5 │ │ │ └────────────────────────────────────────┘ │ │ │ │ Nullable int (int?): │ │ ┌────────────────────────────────────────┐ │ │ │ Can hold a number: 0, 1, -5 │ │ │ │ OR can be empty: null │ │ │ └────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘
Declaring a Nullable Type
Add a question mark ? after any value type to make it nullable.
int regularInt = 5; // must have a value int? nullableInt = null; // can be null double? price = null; bool? isActive = null; DateTime? birthday = null;
Nullable vs Non-Nullable
// This is fine: int? score = null; score = 95; score = null; // set back to null — allowed // This causes a compiler error: int score2 = null; // ❌ regular int cannot be null
Checking for Null
Before using a nullable value, always check if it is null. Accessing .Value on a null nullable throws a runtime exception.
Using HasValue and Value
int? age = null;
if (age.HasValue)
{
Console.WriteLine("Age is: " + age.Value);
}
else
{
Console.WriteLine("Age not provided.");
}
// Output: Age not provided.
HasValue and Value Diagram
┌────────────────────────────────────────────────────────────┐ │ int? age = 25; │ │ │ │ │ ├── age.HasValue → true │ │ └── age.Value → 25 │ ├────────────────────────────────────────────────────────────┤ │ int? age = null; │ │ │ │ │ ├── age.HasValue → false │ │ └── age.Value → ❌ InvalidOperationException │ └────────────────────────────────────────────────────────────┘
The Null-Coalescing Operator ??
The ?? operator provides a default value when a nullable is null. It reads as "if null, use this instead."
int? score = null; int result = score ?? 0; // if score is null, use 0 Console.WriteLine(result); // 0 int? points = 85; int final = points ?? 0; // points is not null, so use 85 Console.WriteLine(final); // 85
?? Operator Flow Diagram
┌────────────────────────────────────────────────────────────┐ │ int result = score ?? 0; │ │ │ │ │ ▼ │ │ Is score null? │ │ / \ │ │ YES NO │ │ │ │ │ │ ▼ ▼ │ │ result = 0 result = score.Value │ └────────────────────────────────────────────────────────────┘
The Null-Coalescing Assignment Operator ??=
The ??= operator assigns a value only if the variable is currently null.
int? count = null; count ??= 10; // count is null, so assign 10 Console.WriteLine(count); // 10 count ??= 99; // count is 10 (not null), skip Console.WriteLine(count); // 10 (unchanged)
Null-Conditional Operator ?.
The ?. operator (called the safe navigation operator) accesses a member only if the object is not null. If it is null, the result is null instead of an exception.
string? name = null; int? length = name?.Length; // no exception — length is null string? city = "London"; int? cityLength = city?.Length; // 6
?. Operator Diagram
┌──────────────────────────────────────────────────────────┐ │ int? length = name?.Length; │ │ │ │ │ ▼ │ │ Is name null? │ │ / \ │ │ YES NO │ │ │ │ │ │ ▼ ▼ │ │ length = null length = name.Length │ └──────────────────────────────────────────────────────────┘
Nullable in Real Code: Database Example
class Employee
{
public string Name;
public int? YearsOfExperience; // optional
public double? Salary; // may not be set yet
}
class Program
{
static void Main()
{
Employee emp = new Employee();
emp.Name = "Sara";
emp.YearsOfExperience = null; // not provided
emp.Salary = 55000.0;
string exp = emp.YearsOfExperience.HasValue
? emp.YearsOfExperience.Value + " years"
: "Not specified";
Console.WriteLine("Name: " + emp.Name);
Console.WriteLine("Experience: " + exp);
Console.WriteLine("Salary: " + (emp.Salary ?? 0));
}
}
// Output:
// Name: Sara
// Experience: Not specified
// Salary: 55000
Nullable Reference Types (C# 8+)
Starting from C# 8, reference types like string and object can also be annotated as nullable using ?. This feature helps you catch null-related bugs at compile time instead of at runtime.
// Without nullable reference types enabled: string name = null; // allowed, but risky // With nullable reference types enabled (C# 8+): string name = null; // ⚠️ compiler warning string? name2 = null; // ✅ explicitly marked as nullable
Quick Reference
┌──────────────────────┬──────────────────────────────────────┐ │ Syntax │ Meaning │ ├──────────────────────┼──────────────────────────────────────┤ │ int? │ Nullable integer │ │ .HasValue │ True if not null │ │ .Value │ Get the actual value (check first) │ │ ?? │ Use fallback if null │ │ ??= │ Assign only if currently null │ │ ?. │ Access member safely (returns null) │ └──────────────────────┴──────────────────────────────────────┘
Nullable types bridge the gap between real-world data — which is often incomplete — and C#'s strict type system. Use them whenever your data might legitimately be absent, and always guard against null before accessing .Value directly.
