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.
3.141.192.120