O'Reilly logo

Visual C# 2005: A Developer's Notebook by Jesse Liberty

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Express Null Values with Nullable Types

With new nullable types, you can assign value types a null value. This can be tremendously powerful, especially when working with databases where the value returned might be null; without nullable types you would have no way to express that an integer value is null, or that a Boolean is neither true nor false.

Note

With nullable types, a value type such as bool or int can have the value null.

How do I do that?

You can declare a nullable type as follows:

System.Nullable<T> variable

Or, if you are within the scope of a generic type or method, you can write:

T? variable

Thus, you can create two Nullable integer variables with these lines of code:

System.Nullable<int> myNullableInt;
int? myOtherNullableInt;

You can check whether a nullable variable is null in two ways as well. You can check like this:

if (myNullableInt.HasValue)

or like this:

if (myNullableInt != null)

Each will return true if the myNullableInt variable is not null, and false if it is, as illustrated in Example 1-7.

Example 1-7. Nullable types

using System;
   
namespace NullableTypes
{
   public class Dog
   {
      private int age;
      public Dog(int age)
      {
         this.age = age;
      }
   }   
   
   class Program
   {
      static void Main(string[  ] args)
      {
         int? myNullableInt = 25;
         double? myNullableDouble = 3.14159;
         bool? myNullableBool = null; // neither yes nor no
   
         // string? myNullableString = "Hello"; // not permitted
         // Dog? myNullableDog = new Dog(3);  // not permitted
   
         if (myNullableInt.HasValue)
         {
            Console.WriteLine("myNullableInt is " + myNullableInt.Value);
         }
         else
         {
            Console.WriteLine("myNullableInt is undefined!");
         }
   
         if (myNullableDouble != null)
         {
            Console.WriteLine("myNullableDouble: " + myNullableDouble);
         }
         else
         {
            Console.WriteLine("myNullableDouble is undefined!");
         }
         
         if ( myNullableBool != null )
         {
            Console.WriteLine("myNullableBool: " + myNullableBool);
         }
         else
         {
            Console.WriteLine("myNullableBool is undefined!");
         }
   
   
         myNullableInt = null;      // assign null to the integer
         // int a = myNullableInt; // won't compile
   
         int b;
         try
         {
            b = (int)myNullableInt;  // will throw an exception if x is null
            Console.WriteLine("b: " + b);
         }
         catch (System.Exception e)
         {
            Console.WriteLine("Exception! " + e.Message);
         }
   
         int c = myNullableInt ?? -1;  // will assign -1 if x is null
   
         Console.WriteLine("c: {0}", c);
   
         // careful about your assumptions here
         // If either type is null, all comparisons evaluate false!
         if (myNullableInt >= c)
         {
            Console.WriteLine("myNullableInt is greater than or equal to c");
         }
         else
         {
            Console.WriteLine("Is myNullableInt less than c?");
         }
   
      }
   }
}

Output:

myNullableInt is 25
myNullableDouble: 3.14159
myNullableBool is undefined!
Exception! Nullable object must have a value.
c: -1
Is myNullableInt less than c?

What just happened?

Let's focus on the Main method. Five nullable types are created:

int? myNullableInt = 25;
double? myNullableDouble = 3.14159;
bool? myNullableBool = null; // neither yes nor no
   
// string? myNullableString = "Hello"; 
// Dog? myNullableDog = new Dog(3);

The first three are perfectly valid, but you cannot create a nullable string or a nullable user-defined type (class), and thus they should be commented out.

Note

However, structs can be user-defined, and it's OK to use them as nullables.

We check whether each nullable type is null (or, equivalently, whether the HasValue property is true). If so, we print their value (or equivalently, we access their Value property).

After this the value null is assigned to myNullableInt:

myNullableInt = null;

The next line would like to declare an integer and initialize it with the value in myNullableInt, but this is not legal; there is no implicit conversion from a nullable int to a normal int. You can solve this in two ways. The first is with a cast:

b = (int)myNullableInt;

This will compile, but it will throw an exception at runtime if myNullableInt is null (which is why we've enclosed it in a try/catch block).

The second way to assign a nullable int to an int is to provide a default value to be used in case the nullable int is null:

int c = myNullableInt ?? -1;

This line reads as follows: "initialize int c with the value in myNullableInt unless myNullableInt is null, in which case initialize c to -1."

Note

Comparison operators always return false if one value is null!

It turns out that all the comparison operators (>, <, <=, etc.) return false if either value is null. Thus, a true value can be trusted:

if (myNullableInt >= c)
{
   Console.WriteLine("myNullableInt is greater than or equal to c");
}

Warning

Note, however, that = = will return true if both arguments are null.

If the statement "myNullableInt is greater than or equal to c" displays, you know that myNullableInt is not null, nor is c, and that myNullableInt is greater than c. However, a false value cannot be trusted in the normal fashion:

else
{
   Console.WriteLine("Is myNullableInt less than c?");
}

This else clause can be reached if myNullableInt is less than c, but it can also be reached if either myNullableInt or c is null.

What about...

...Boolean null values? How are they compared to correspond to the SQL three-value Boolean type?

C# provides two new operators:

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

You can use these operators to create the truth table depicted in Table 1-1.

Table 1-1. Truth table for nullable Boolean operators

If x is...

And y is...

x and y evaluate to...

x|y evaluates to...

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

Where can I learn more?

The Visual C# Developer Center has a good article on nullable types. Visit http://msdn.microsoft.com/vcsharp/2005/overview/language/nullabletypes/ for more information.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required