Using nullable types (C# Programming Guide)

Nullable types are types that represent all the values of an underlying value type T, and an additional null value. For more information, see the Nullable types topic.

You can refer to a nullable type in any of the following forms: Nullable<T> or T?. These two forms are interchangeable.

Declaration and assignment

As a value type can be implicitly converted to the corresponding nullable type, you assign a value to a nullable type as you would for its underlying value type. You also can assign the null value. For example:

double? pi = 3.14;
char? letter = 'a';

int m2 = 10;
int? m = m2;

bool? flag = null;

// Array of nullable type:
int?[] arr = new int?[10];

Examination of a nullable type value

Use the following readonly properties to examine an instance of a nullable type for null and retrieve a value of an underlying type:

The code in the following example uses the HasValue property to test whether the variable contains a value before displaying it:

int? x = 10;
if (x.HasValue)
{
    Console.WriteLine($"x is {x.Value}");
}
else
{
    Console.WriteLine("x does not have a value");
}

You also can compare a nullable type variable with null instead of using the HasValue property, as the following example shows:

int? y = 7;
if (y != null)
{
    Console.WriteLine($"y is {y.Value}");
}
else
{
    Console.WriteLine("y does not have a value");
}

Beginning with C# 7.0, you can use pattern matching to both examine and get a value of a nullable type:

int? z = 42;
if (z is int valueOfZ)
{
    Console.WriteLine($"z is {valueOfZ}");
}
else
{
    Console.WriteLine("z does not have a value");
}

Conversion from a nullable type to an underlying type

If you need to assign a nullable type value to a non-nullable type, use the null-coalescing operator ?? to specify the value to be assigned if a nullable type value is null (you also can use the Nullable<T>.GetValueOrDefault(T) method to do that):

int? c = null;

// d = c, if c is not null, d = -1 if c is null.
int d = c ?? -1;
Console.WriteLine($"d is {d}");

Use the Nullable<T>.GetValueOrDefault() method if the value to be used when a nullable type value is null should be the default value of the underlying value type.

You can explicitly cast a nullable type to a non-nullable type. For example:

int? n = null;

//int m1 = n;    // Doesn't compile.
int n2 = (int)n; // Compiles, but throws an exception if n is null.

At run time, if the value of a nullable type is null, the explicit cast throws an InvalidOperationException.

A non-nullable value type is implicitly converted to the corresponding nullable type.

Operators

The predefined unary and binary operators and any user-defined operators that exist for value types may also be used by nullable types. These operators produce a null value if one or both operands are null; otherwise, the operator uses the contained values to calculate the result. For example:

int? a = 10;
int? b = null;
int? c = 10;

a++;        // a is 11.
a = a * c;  // a is 110.
a = a + b;  // a is null.

For the relational operators (<, >, <=, >=), if one or both operands are null, the result is false. Do not assume that because a particular comparison (for example, <=) returns false, the opposite comparison (>) returns true. The following example shows that 10 is

  • neither greater than or equal to null,
  • nor less than null.
int? num1 = 10;
int? num2 = null;
if (num1 >= num2)
{
    Console.WriteLine("num1 is greater than or equal to num2");
}
else
{
    Console.WriteLine("num1 >= num2 is false (but num1 < num2 also is false)");
}

if (num1 < num2)
{
    Console.WriteLine("num1 is less than num2");
}
else
{
    Console.WriteLine("num1 < num2 is false (but num1 >= num2 also is false)");
}

if (num1 != num2)
{
    Console.WriteLine("num1 != num2 is true!");
}

num1 = null;
if (num1 == num2)
{
    Console.WriteLine("num1 == num2 is true if the value of each is null");
}
// Output:
// num1 >= num2 is false (but num1 < num2 also is false)
// num1 < num2 is false (but num1 >= num2 also is false)
// num1 != num2 is true!
// num1 == num2 is true if the value of each is null

The above example also shows that an equality comparison of two nullable types that are both null evaluates to true.

Boxing and unboxing

A nullable value type is boxed by the following rules:

  • If HasValue returns false, the null reference is produced.
  • If HasValue returns true, a value of the underlying value type T is boxed, not the instance of Nullable<T>.

You can unbox the boxed value type to the corresponding nullable type, as the following example shows:

int a = 41;
object aBoxed = a;
int? aNullable = (int?)aBoxed;
Console.WriteLine($"Value of aNullable: {aNullable}");

object aNullableBoxed = aNullable;
if (aNullableBoxed is int valueOfA)
{
    Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}
// Output:
// Value of aNullable: 41
// aNullableBoxed is boxed int: 41

The bool? type

The bool? nullable type can contain three different values: true, false and null. The bool? type is like the Boolean variable type that is used in SQL. To ensure that the results produced by the & and | operators are consistent with the three-valued Boolean type in SQL, the following predefined operators are provided:

  • bool? operator &(bool? x, bool? y)
  • bool? operator |(bool? x, bool? y)

The semantics of these operators is defined by the following table:

x y x&y x|y
true true true true
true false false true
true null null true
false true false true
false false false false
false null false null
null true null true
null false false null
null null null null

Note that these two operators don't follow the rules described in the Operators section: the result of an operator evaluation can be non-null even if one of the operands is null.

See Also