The Basics

Nullable types are instances of the System.Nullable generic structure type. They can represent all the values of an underlying type plus an additional null value. The reason for using nullable types is to overcome the issue of not being able to easily determine if a value type is empty or undefined. Unlike reference types - which can be assigned a null value - null is not assignable to primitive value types.
Use nullable types as a consistent solution for determining whether a value type is either empty or undefined.

Declaration

You can declare nullable types in one of two ways:
System.Nullable variableName;   // method 1
 
T? variableName; // method 2
Where T is the underlying type of the nullable type. T can be any value type including struct. For example:
Nullable i = null;
int? j = 10;
double? d1 = 3.14;
bool? flag = null;
char? letter = 'a';
int?[] arr = new int?[10];


Properties

Each instance of a nullable type has two public read-only properties:
  • HasValue - Type is bool. True if the variable contains a non-null value. For example:
int? x = 10;
if (x.HasValue)
{ System.Console.WriteLine (x.Value); }
else
{ System.Console.WriteLine ("Undefined"); }
  • Value - Type is the underlying type. If HasValue is true, then Value contains a meaningful value. If HasValue is false, accessing Value will throw an InvalidOperationException.


Useful methods

  • GetType - Gets the Type of the underlying value type.
  • GetValueOrDefault() - Retrieves the value of the current Nullable object, or the object's default value.
  • GetValueOrDefault(T defaultValue) - Retrieves the value of the current Nullable object, or the specified defaultValue if the value of the object is null. For example:
float? mySingle = null;
float? yourSingle = -1.0f;
 
yourSingle = mySingle.GetValueOrDefault(-333.33f);
 
// yourSingle now equals -333.33f


Boxing and Unboxing

When a nullable type is boxed (cast to a reference type), only the value of the nullable type is boxed. So if HasValue is true, the value of Value is boxed. If HasValue is false, a null reference is boxed. When the resulting object is unboxed, a new nullable type is created, and HasValue and Value are populated appropriately.
To convert a nullable type back to the primitive type on which it is based, you can use the function System.Nullable.GetValueOrDefault().
int? NullableNumber = null; 
int Number = NullableNumber.GetValueOrDefault(); // Default value is 0
NullableNumber = 146;
Number = NullableNumber.GetValueOrDefault(); // Value is 146
However, if you want to specify your own default value, you can either specify a default value or use the ?? operator. The ?? operator will return the value if it is not null or the given value on the right side of the ??.
int? NullableNumber = null; 
int Number = NullableNumber.GetValueOrDefault(-1); // Number is -1
NullableNumber = 146;
Number = NullableNumber.GetValueOrDefault(-1); // Number is 146
 
// Is the same as
 
int? NullableNumber = null;
int Number = NullableNumber ?? -1; // Number is -1
NullableNumber = 146;
Number = NullableNumber ?? -1; // Number is 146

MSDN references