Using Nullable Types (C# Programming Guide)

Nullable types can represent all the values of an underlying type, and an additional null value. Nullable types are declared in one of two ways:

System.Nullable<T> variable

-or-

T? variable

T is the underlying type of the nullable type. T can be any value type including struct; it cannot be a reference type.

For an example of when you might use a nullable type, consider how an ordinary Boolean variable can have two values: true and false. There is no value that signifies "undefined". In many programming applications, most notably database interactions, variables can occur in an undefined state. For example, a field in a database may contain the values true or false, but it may also contain no value at all. Similarly, reference types can be set to null to indicate that they are not initialized.

This disparity can create extra programming work, with additional variables used to store state information, the use of special values, and so on. The nullable type modifier enables C# to create value-type variables that indicate an undefined value.

Any value type may be used as the basis for a nullable type. For example:

int? i = 10;
double? d1 = 3.14;
bool? flag = null;
char? letter = 'a';
int?[] arr = new int?[10];

Each instance of a nullable type has two public read-only properties:

  • HasValue

    HasValue is of type bool. It is set to true when the variable contains a non-null value.

  • Value

    Value is of the same type as the underlying type. If HasValue is true, Value contains a meaningful value. If HasValue is false, accessing Value will throw a InvalidOperationException.

In this example, the HasValue member is used to test whether the variable contains a value before it tries to display it.

int? x = 10;
if (x.HasValue)
{
    System.Console.WriteLine(x.Value);
}
else
{
    System.Console.WriteLine("Undefined");
}

Testing for a value can also be done as in the following example:

int? y = 10;
if (y != null)
{
    System.Console.WriteLine(y.Value);
}
else
{
    System.Console.WriteLine("Undefined");
}

A nullable type can be cast to a regular type, either explicitly with a cast, or by using the Value property. For example:

int? n = null;

//int m1 = n;      // Will not compile. 
int m2 = (int)n;   // Compiles, but will create an exception if n is null. 
int m3 = n.Value;  // Compiles, but will create an exception if n is null.

If a user-defined conversion is defined between two data types, the same conversion can also be used with the nullable versions of these data types.

A variable of nullable type can be set to null with the null keyword, as shown in the following example:

int? n1 = null;

The conversion from an ordinary type to a nullable type, is implicit.

int? n2;
n2 = 10;  // Implicit conversion.

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 the operands are null; otherwise, the operator uses the contained value to calculate the result. For example:

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

a++;         // Increment by 1, now a is 11.
a = a * 10;  // Multiply by 10, now a is 110.
a = a + b;   // Add b, now a is null.

When you perform comparisons with nullable types, if the value of one of the nullable types is null and the other is not, all comparisons evaluate to false except for != (not equal). It is important not to assume that because a particular comparison returns false, the opposite case returns true. In the following example, 10 is not greater than, less than, nor equal to null. Only num1 != num2 evaluates to true.

int? num1 = 10;
int? num2 = null;
if (num1 >= num2)
{
    Console.WriteLine("num1 is greater than or equal to num2");
}
else
{
    // This clause is selected, but num1 is not less than num2.
    Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");
}

if (num1 < num2)
{
    Console.WriteLine("num1 is less than num2");
}
else
{
    // The else clause is selected again, but num1 is not greater than 
    // or equal to num2.
    Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");
}

if (num1 != num2)
{
    // This comparison is true, num1 and num2 are not equal.
    Console.WriteLine("Finally, num1 != num2 returns true!");
}

// Change the value of num1, so that both num1 and num2 are null.
num1 = null;
if (num1 == num2)
{
    // The equality comparison returns true when both operands are null.
    Console.WriteLine("num1 == num2 returns true when the value of each is null");
}

/* Output:
 * num1 >= num2 returned false (but num1 < num2 also is false)
 * num1 < num2 returned false (but num1 >= num2 also is false)
 * Finally, num1 != num2 returns true!
 * num1 == num2 returns true when the value of each is null
 */

An equality comparison of two nullable types that are both null evaluates to true.

The ?? operator defines a default value that is returned when a nullable type is assigned to a non-nullable type.

int? c = null;

// d = c, unless c is null, in which case d = -1. 
int d = c ?? -1;

This operator can also be used with multiple nullable types. For example:

int? e = null;
int? f = null;

// g = e or f, unless e and f are both null, in which case g = -1. 
int g = e ?? f ?? -1;

The bool? nullable type can contain three different values: true, false and null. For information about how to cast from a bool? to a bool, see How to: Safely Cast from bool? to bool (C# Programming Guide).

Nullable Booleans are 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 results of these operators are listed in 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

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft