11.2. Nullable Types

Any developer who has worked with a database understands some of the pain that goes into aligning business objects with database schemas. One of the difficulties has been that the default value for a database column could be nothing (as in not specified), even if the column was an integer. In .NET, value types, such as integers, always have a value. When pulling information from the database, it was necessary to add additional logic that would maintain state for the database columns to indicate whether a value had been set. Two of the most prominent solutions to this problem were to either adjust the database schema to prevent nothing values, which can be an issue where a field is optional, or to add a Boolean flag for every field that could be nothing, which added considerable amounts of code to even a simple application.

Generic types provide a mechanism to bridge this divide in quite an efficient manner, using the generic Nullable type. The Nullable type is a generic structure that has a single Type parameter, which is the type it will be wrapping. It also contains a flag indicating whether a value exists, as shown in the following snippet:

Public Structure Nullable(Of T As Structure)
    Private m_hasValue As Boolean
    Private m_value As T

    Public Sub New(ByVal value As T)
        Me.m_value = value
        Me.m_hasValue = True
    End Sub

    Public ReadOnly Property HasValue() As Boolean
        Get
            Return Me.m_hasValue
        End Get
    End Property

    Public ReadOnly Property Value() As T
        Get
            If Not Me.HasValue Then
               Throw new Exception("...")
            End If
            Return Me.m_value
        End Get
    End Property

    Public Function GetValueOrDefault() As T
        Return Me.m_value
    End Function

    Public Function GetValueOrDefault(ByVal defaultValue As T) As T
        If Not Me.HasValue Then
            Return defaultValue
        End If
        Return Me.m_value
    End Function

Public Shared Narrowing Operator CType(ByVal value As Nullable(Of T)) As T
        Return value.m_value
    End Operator

    Public Shared Widening Operator CType(ByVal value As T) As Nullable(Of T)
        Return New Nullable(Of T)(value)
    End Operator
End Structure

This code indicates how you can create a new Nullable type by specifying a Type argument and calling the constructor. However, the last two methods in this structure are operators that allow conversion between the Nullable type and the Type argument provided. Conversion operators are covered later in this chapter, but for now it is sufficient to understand that conversion from the Type argument to a Nullable type is allowed using implicit conversion, whereas the reverse requires explicit casting. You can also see that the Type parameter, T, is constrained to be a structure. Because class variables are object references, they are implicitly nullable.

The following example creates and uses a Nullable type. You can see that C# has additional support for Nullable types with an abbreviated syntax when working with the Nullable type:

C#

Nullable<int>x=5;
int? y,z;
if (x.HasValue)
    y=x.Value;
else
    y=8;
z=x?? + y??7;
int? w = x + y;

VB.NET

Dim x, y As Nullable(Of Integer)
Dim z as Integer?
x = 5
If x.HasValue Then
    y = x.Value
Else
    y = 8
End If
z = x.GetValueOrDefault + y.GetValueOrDefault(7)
Dim w as Integer = x + y

In these examples, both languages can use the HasValue property to determine whether a value has been assigned to the Nullable type. If it has, the Value property can be used to retrieve the underlying value. The Value property throws an exception if no value has been specified. Having to test before you access the Value property is rather tedious, so the GetValueOrDefault function was added. This retrieves the value if one has been supplied; otherwise, it returns the default value. There are two overloads to this method, with and without an alternative value. If an alternative value is supplied, this is the default value that is returned if no value has been supplied. Alternatively, the default value is defined as the zero-initialized underlying type. For example, if the underlying type were a Point, made up of two double values, the default value would be a Point with both values set to zero.

Both C# and VB.NET have abbreviations to make working with Nullable types easier. Nullable<int> or Nullable(of Integer) can be abbreviated as int? and Integer?, which defines a Nullable integer variable. The second abbreviation (C# only) is the null coalescing operator, ??. This is used to abbreviate the GetValueOrDefault function. Finally the last line of both snippets shows an interesting feature, which is support for null propagation. If either x or y are null, the null value propagates to w. This is the equivalent of the following:

C#

int? w = x.HasValue && y.HasValue ? x.Value + y.Value : (int?)null;

VB.NET

Dim w as Integer? = CInt(If(x.HasValue and y.HasValue, x.Value + y.Value, Nothing))

Null propagation can lead to unexpected results and should be used with extreme caution. As a null value anywhere in an extended calculation can lead to a null result, it can be difficult to identify any errors.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.192.120