Nullable<T> and the ?? operator
Nullable value types
The concept of a null
value is simple: it denotes the absence of a value. In the first version of C#, you could not have null
value types. However, C# 2.0 introduced the Nullable<T>
type to remedy this:
Nullable<int> nullInt = new Nullable<int>();
nullInt.HasValue; // Returns false
nullInt.Value; // Throws exception as no value has been set
Nullable<int> nonNullInt = new Nullable<int>(2);
nonNullInt.HasValue; // Returns true
nonNullInt.Value; // Returns 2
You can also directly assign or retrieve the value:
Nullable<int> nullInt = null;
Nullable<double> nonNullDouble = 2.0;
Even better, appending the ? keyword to a type makes it a Nullable<T>
:
int? nullInt = 2; // Type is Nullable<int>
bool? nonNullBool = true; // Type is Nullable<bool>
Comparing nullable types also works as expected:
int? nullInt = null;
int? nonNullInt = 2;
nullInt == null; // Returns true
nonNullInt == 2; // Returns true
nonNullInt == null; // Returns false
The Nullable<T>
class itself is implemented as a value type, so can we create a nullable Nullable<T>
? Let’s try:
Nullable<Nullable<int>> nullableInception = null;
It turns out we can’t; the above code does not compile. This is due to the fact that the Nullable<T>
struct does not allow nullable types to be specified as its generic type parameter (see MSDN).
The ?? operator
Besides adding Nullable<T>
, C# 2.0 introduced another feature that deals with null
values: the ?? operator (also known as the null-coalescing operator). It returns the left-hand operand if that is not null; otherwise it returns the right hand operand. This simple operator can greatly simplify your null
checks:
public static string NullCheckWithIfStatement()
{
if (str == null)
{
return string.Empty;
}
return str;
}
public static string NullCheckWithTernaryOperator()
{
return str == null ? string.Empty : str;
}
public static string NullCheckWithNullCoalescingOperator()
{
return str ?? string.Empty;
}
The ?? operator manages to be both concise and very readable.
With more complex statements, the difference becomes even more striking:
public static string ComplexNullCheckWithIfStatement()
{
string result1 = GetPotentiallyNullString1();
if (result1 != null)
{
return result1;
}
string result2 = GetPotentiallyNullString2();
if (result2 != null)
{
return result2;
}
return string.Empty;
}
public static string ComplexNullCheckWithNullCoalescingOperator()
{
return GetPotentiallyNullString1() ??
GetPotentiallyNullString2() ??
string.Empty;
}
Of course, you can also use it on Nullable<T>
values:
int? nullInt = null;
int? nonNullInt = 2;
nullInt ?? 8; // Returns 8
nonNullInt ?? 5; // Returns 2
If you use the ?? operator to return a type’s default value, you can also use the GetValueOrDefault()
method:
int? nullInt = null;
int? nonNullInt = 2;
nullInt.GetValueOrDefault(); // Returns 0
nullInt ?? default(int); // Returns 0
nonNullInt.GetValueOrDefault(); // Returns 2
nonNullInt ?? default(int); // Returns 2
Conclusion
Adding support for nullable value types was a very useful addition to C#. I use it often when dealing with databases, where nullable value types are common.
The ?? operator is a personal favorite of mine due to its conciseness and usefulness.