A data type is said to be nullable if it can be assigned a value or a null reference. Reference types, such as strings and class types, are nullable; they can be set to a null reference, and the result is a null value. Value types, such as integers, Booleans, and dates, are not nullable. If you set a value type to a null reference, the result is a default value, such as 0 or false.
Try this:
In C#:
int i = null;
Boolean b = null;
DateTime d = null;
Debug.WriteLine(i + ", " + b + ", " + d.ToShortDateString());
In VB:
Dim i As Integer = Nothing
Dim b As Boolean = Nothing
Dim d As DateTime = Nothing
Debug.WriteLine(i & ", " & b & ", " & d.ToShortDateString)
The C# code will generate compile-time errors saying you cannot convert null to the defined type because it is a non-nullable value type.
VB, however, will display this:
0, False, 1/1/0001
Instead of retaining a null value, VB sets the variable to the default value.
A value type can express only the values appropriate to its type; there is no easy way for a value type to understand that it is null.
There may be cases, however, when you need your code to really handle a null as a null and not as a default value. It would be odd, for example, to handle a null date by hard-coding a check for the 1/1/0001 date.
The .NET Framework 2.0 introduced a Nullable class and an associated Nullable structure. The Nullable structure includes the value type itself and a field identifying whether the value is null. A variable of a Nullable type can represent all the values of the underlying type, plus an additional null value. The Nullable structure supports only value types because reference types are nullable by design.
To make a value type property nullable, you need to declare it using the Nullable structure. However, you still want your property to be strongly typed as an integer, date, Boolean, or the appropriate underlying type. The ability to use a class or structure for only a specific type of data is the purpose of generics.
Generics allow you to tailor a class, structure, method, or interface to a specific data type. So you can create a class, structure, method, or interface with generalized code. When you use it, you define that it can work only on a particular data type. This gives you greater code reusability and type safety.
The .NET Framework built-in Nullable structure is generic. When you use the structure, you define the particular data type to use. As a specific example, an InventoryDate property that allows the date to be a date or a null value uses the generic Nullable structure as follows:
In C#:
public Nullable<DateTime> InventoryDate { get; set; }
In VB:
Private _InventoryDate As Nullable(Of DateTime)
Public Property InventoryDate() As Nullable(Of DateTime)
Get
Return _InventoryDate
End Get
Set(ByVal value As Nullable(Of DateTime))
_InventoryDate = value
End Set
End Property
Notice the syntax of the Nullable structure. Since it is a generic structure, it has the standard <T> [C#] or (Of T) [VB] syntax, where T is the specific data type you want it to accept. In this case, the Nullable structure supports dates, so the <DateTime> or (Of DateTime) syntax is used. This ensures that the Nullable structure contains only a date or a null value.
More commonly, however, the nullable structure is defined using the question mark (?) short-hand syntax:
In C#:
public DateTime? InventoryDate { get; set; }
In VB:
Private _InventoryDate As DateTime?
Public Property InventoryDate() As DateTime?
Get
Return _InventoryDate
End Get
Set(ByVal value As DateTime?)
_InventoryDate = value
End Set
End Property
Both examples work the same way, but many developers prefer the shorter, question mark syntax.
You can then use this property in your application as needed. For
example:
In C#:
Product prod = new Product();
if (prod.InventoryDate.HasValue)
{
if (prod.InventoryDate.Value < DateTime.Now.Date.AddDays(-10))
{
MessageBox.Show("Need to do an inventory");
}
}
else
{
MessageBox.Show("Need to do an inventory - never been done");
}
In VB:
Dim prod As New Product
If prod.InventoryDate.HasValue Then
If prod.InventoryDate.Value < Now.Date.AddDays(-10) Then
MessageBox.Show("Need to do an inventory")
End If
Else
MessageBox.Show("Need to do an inventory - never been done")
End If
The HasValue property of the Nullable class defines whether the value type has a value—in other words, whether it is null. If it does have a value, you can retrieve the value using the Value property of the Nullable class.
The Nullable structure is exceptionally useful when you’re working with databases, because empty fields in a database are often null. Assuming that you have an InventoryDate fi eld in a table, you could write code as follows:
In C#:
prod.InventoryDate =
dt.Rows[0]["InventoryDate"] == DBNull.Value ?
null :
(DateTime?)dt.Rows[0]["InventoryDate"];
In VB:
prod.InventoryDate = _
If(dt.Rows(0).Item("InventoryDate") Is DBNull.Value, _
Nothing, _
CType(dt.Rows(0)("InventoryDate"), DateTime))
The ternary operator is required here because you cannot convert a DBNull
to a date, so you need to ensure that it is not a null.
Use the Nullable structure any time you need to support nulls in a
value type, such as an integer, Boolean, or date.
(Based on an except from "Doing Objects in Visual Basic 2005".)
Enjoy!