CodeGym /Courses /C# SELF /Nullable Types for Value Types

Nullable Types for Value Types

C# SELF
Level 14, Lesson 0
Available

1. Intro

Let's imagine this situation. You're storing data about cats in your code. And besides, say, the cat's age, you also want to store states like "no data", "age unknown". You could store 0, but zero is a totally valid age.

int age = 0; // Cat's age. But what does 0 mean? Is it a kitten or "unknown"?

The problem is, int only takes integer values, and "no data" isn't one of them. If age was a string, you could assign null. But with numbers, that trick doesn't work:

int age = null; // Error! You can't assign null to a variable of type int

That's because value types (structs like int, double, DateTime, bool) always store something. They don't have an "empty" state (unlike reference types, where null just means no object).

Real-life example:
Trying to get around this, devs sometimes invent "special" values: like -1 or int.MaxValue for "no value". But that's ugly, inconvenient, and risky: it's easy to mix up a real value with a placeholder.

2. Nullable Type: a type that can be "null"

The Idea

What if we let regular numbers (and all value types, really) store not just a value, but also null?
In C#, this is done with a special wrapper class Nullable<T>. This class can hold either a value of type T, or nothing (meaning null).

Syntax

int? age = null; // The age variable can be a number or null
Declaring a nullable type using ?

When the C# compiler sees this, it actually treats it as:

Nullable<int> age = new Nullable<int>(); // The age variable doesn't have a value

Or, if you want to set a value explicitly:

Nullable<int> age = new Nullable<int>(42); // age holds the number 42

So, the question mark turns any value type into its nullable version:

  • int? (same as Nullable<int>)
  • double?
  • DateTime?
  • and any other struct

Nullable wrappers for the most popular struct types

Regular Type Nullable Type Example
int
int?
int? a = null;
double
double?
double? x = 3.14;
bool
bool?
bool? ok = null;
DateTime
DateTime?
DateTime? d = null;

You can also write it the long way, using the wrapper class:


Nullable<int> pages = null;
        
Long form

But writing int? is shorter, and honestly, cooler.

3. How to use a nullable type

Assigning and checking

Assigning null works just like with reference types:

Declaration and assignment

int? temperature = null;
temperature = 25;

Checking for null

How do you know if your nullable type actually has a value?

if (temperature != null)
{
    Console.WriteLine($"Temperature: {temperature}");
}
else
{
    Console.WriteLine("No temperature data");
}

Nullable type properties: .HasValue and .Value

Nullable types have two important properties:

  • .HasValue — returns true if the variable has something in it (not null).
  • .Value — the value itself, if it exists (otherwise you'll get an exception).
int? temperature = null;
if (temperature.HasValue) //no exception here!
{
    Console.WriteLine($"Temperature: {temperature.Value}°C");
}
else
{
    Console.WriteLine("Temperature unknown");
}

This code will work: temperature isn't null, it holds null inside. And you can always call the HasValue property on a Nullable type. But trying to get .Value when it's not there? Bad idea, you'll get an InvalidOperationException. Always check for a value first!

Shorter output syntax

A lot of times, you can just use the nullable variable — and C# will figure it out:

int? hours = null;
Console.WriteLine(hours); // prints nothing (just blank)
hours = 10;
Console.WriteLine(hours); // prints 10

4. Operations and nullable types: math, comparisons, conversions

Operations: what happens?

If one of the operands is nullable, the result is also nullable.
And if one of the operands is null, the result is also null.

int? a = 5;
int? b = null;
int? sum = a + b; // sum == null

int? c = 10;
int? d = 15;
int? total = c + d; // total == 25

Comparison operations

You can compare nullable types with regular numbers:

int? score = null;
if (score > 0) Console.WriteLine("Awesome result!");
else Console.WriteLine("No result"); // This branch will run

If score is null, the condition score > 0 will be false.

Explicit and implicit conversion

  • From regular type to nullable: automatic.
  • From nullable to regular: only if it's not null (otherwise, exception).
int? x = 3;
int y = x.Value; // Ok, if x isn't null

// Implicit
int? z = y;

5. Nullable and methods: parameters and return values

Returning nullable values

If a method can't always return a result, use nullable types as the return value:

// The method looks for a user by login and returns their age if found, otherwise null
int? FindUserAge(string login)
{
    // ... search logic here
    return null; // if not found
}

Nullable parameters

You can accept nullable values as parameters, to make it clear: "might be there, might not".

void PrintTemperature(int? temp)
{
    if (temp == null)
        Console.WriteLine("Temperature unknown");
    else
        Console.WriteLine($"Temperature: {temp} degrees");
}
2
Task
C# SELF, level 14, lesson 0
Locked
Nullable types: declaration and check
Nullable types: declaration and check
2
Task
C# SELF, level 14, lesson 0
Locked
Arithmetic with nullable types
Arithmetic with nullable types
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION