Skip to content

C# - Nullables

In programming, null represents the absence of a value. Handling null correctly is crucial for writing robust and bug-free applications. C# provides a powerful set of features to manage null, primarily through nullable value types and nullable reference types.

By default, value types like int, double, bool, and DateTime cannot be null. They must always hold a value. However, sometimes you need to represent an ‘unassigned’ or ‘unknown’ state, for example, a non-required field in a database.

To allow a value type to hold null, you can declare it as a nullable value type by adding a ? after the type name.

// A regular int cannot be null
// int age = null; // Compile-time error
// A nullable int can be null
int? age = null;
bool? isOptedIn = true;
double? temperature = 21.5;
temperature = null; // This is valid

Nullable types have two important properties:

  • HasValue: A boolean that is true if the variable holds a value, and false if it is null.
  • Value: Returns the underlying value. Throws an InvalidOperationException if you try to access it when HasValue is false.
int? middleNameLength = null;
if (middleNameLength.HasValue)
{
Console.WriteLine($"Length is: {middleNameLength.Value}");
}
else
{
Console.WriteLine("No middle name length provided.");
}

Introduced in C# 8, Nullable Reference Types (NRTs) are a game-changer for preventing NullReferenceException, one of the most common runtime errors. This feature helps you express your intent about whether a variable (like a string or a custom class object) is allowed to be null.

To enable NRTs, add the following line to your .csproj project file:

<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>

With NRTs enabled:

  • string name: This is a non-nullable reference type. The compiler will warn you if you don’t initialize it or if you try to assign null to it.
  • string? nickname: This is a nullable reference type. It is explicitly allowed to be null.
#nullable enable // You can also enable this for a single file
string requiredField = "Some value";
// requiredField = null; // Generates a compiler warning!
string? optionalField = null; // This is allowed
// Compiler warns you that optionalField might be null here!
// Console.WriteLine(optionalField.Length);
// You must check for null before using it
if (optionalField != null)
{
Console.WriteLine(optionalField.Length); // No warning here
}

C# provides several convenient operators for working with nullable types.

The ?? operator provides a default value for a nullable type if it is null. It reads as “if the left-hand side is not null, use it; otherwise, use the right-hand side.”

string? userName = null;
// If userName is null, use "Guest". Otherwise, use userName's value.
string displayName = userName ?? "Guest";
Console.WriteLine(displayName); // Output: Guest

The ??= operator (C# 8+) assigns the right-hand value to the left-hand variable only if the left-hand variable is null.

List<int>? numbers = null;
// If numbers is null, create a new list and assign it to numbers.
numbers ??= new List<int>();
numbers.Add(42);
Console.WriteLine(numbers.Count); // Output: 1

The ?. and ?[] operators (C# 6+) allow you to access members or elements of a variable only if that variable is not null. If the variable is null, the expression short-circuits and returns null.

string? name = null;
// If name is null, length will be null. Otherwise, it will be name.Length.
int? length = name?.Length;
Console.WriteLine(length); // Output: (nothing, because length is null)
name = "Alice";
length = name?.Length;
Console.WriteLine(length); // Output: 5
// Works with arrays and indexers too
string[]? names = { "Alice", "Bob" };
string? first = names?[0]; // "Alice"
names = null;
first = names?[0]; // first becomes null, no exception is thrown

Always enable Nullable Reference Types in your modern C# projects. It is one of the single most effective features for improving code quality and preventing runtime errors.