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.

Leave a Comment

Your email address will not be published. Required fields are marked *