Working with value types and data can sometimes be challenging because a value type doesn't normally hold a null value. This lesson show you how to overcome this limitation with C# nullable types. Here's what you'll learn.
- Understand the problem that nullable types solve
- See how to declare a nullable type
- Learn how to use nullable types
Understanding the Problem with Value Types and Null Values
As explained in Lesson 12: Structs, the default value of a struct (value type) is some form of 0. This is another difference between reference types and value types, in addition to what was described in Lesson 22: Topics on C# Type. The default value of a reference type is null. If you're just writing C# code and managing your own data source, such as a file that holds data for your application, the default values for structs works fine.
In reality, most applications work with databases, which have their own type systems. The implications of working with database type systems is that you don't have a one-to-one mapping between C# and database types. One glaring difference is that database types can be set to null. A database has no knowledge of reference and value types, which are C# language (.NET Platform) concepts. This means that C# value type equivalents in the database, such as int, decimal, and DateTime, can be set to null.
Since a type in the database can be null, but your C# value type can't be null, you have to find some way to provide a translation in your C# code to account for null values. Effectively, the scheme you use will often be inconsistent from one program to another; something you often don't have a choice about. For example, what if you wanted to handle a null DateTime from SQL Server as the minimum DateTime value in C#. After that project, your next task would be to read data from a legacy Foxpro database, whose minimum DateTime value is different from SQL Server. Because of this lack of constency and potential confusion, C# 2.0 added nullable types, which are more elegant and natural for working with null data.
Declaring Nullable Types
To declare a value type as nullable, append a question mark, ?, to the type name. Here's how to declare a DateTime variable as a nullable type:
A DateTime can't normally hold a null value, but the declaration above enables startDate to hold null, as well as any legal DateTime value. The proper terminology is to refer to the type of startDate as a nullable DateTime.
You can assign a normal value to startDate like this:
startDate = DateTime.Now;
or you can assign null, like this:
startDate = null;
Here's another example that declares and initializes a nullable int:
int? unitsInStock = 5;
The unitsInStock in the example above can be assigned a value of null also.
Working with Nullable Types
When you have nullable types, you'll want to check them to see if they're null. Here's an example that shows how you can check for a null value:
bool isNull = startDate == null;
Console.WriteLine("isNull: " + isNull);
The example above shows that you only need to use the equals operator to check for null. You could also make the equality check as part of an if statement, like this:
if (unitsInStock == null)
availableUnits = 0;
availableUnits = (int)unitsInStock;
Note: Notice the cast operator in the else clause above. An explicit conversion is required when assigning from nullable to non-nullable types.
That's several lines of code for something that appears to be such a common operation. Fortunately, there's a better way to perform the same task, using the coalesce operator, ??, shown below:
int availableUnits = unitsInStock ?? 0;
The coalesce operator works like this: if the first value (left hand side) is null, then C# evaluates the second expression (right hand side).