Background
Something I have always been a bit disappointed with in .net is the handling for dates with null values. I know you can use
Nullable(Of
Date) or
Nullable(Of
DateTime) (or i C#
date? or
Datetime?), but what I want is a date object that I can set a date value, set to Nothing or set to be equal to DBNull.Value.
So I thought I would document my path to creating the object I need. The code will be in VB.Net as that is what I curently have to use at my place of work.
Nullable Base Object.
First of all as I may need other objects like Int32s and Strings to be nullable in the future I'll create a nullable base object which all my new objects can inherit from and will contain some basic implementation. First I am going to create a class and declare it MustInherit (abstract)so that cannot be used on its own. This will be the base object that any or all of my nullable objects will inherit from.
Option Explicit On
Option Strict On
''' <summary>
''' This object is the object that all nullable objects should inherit from.
''' </summary>
Public MustInherit Class NullableBaseObject
Implements System.Data.SqlTypes.INullable
#Region "Declarations"
Protected _isNull As Boolean
#End Region
#Region "Properties"
''' <summary>
''' Gets a value indicating whether this instance has value.
''' </summary>
''' <value><c>true</c> if this instance has value; otherwise, false.</value>
Public ReadOnly Property HasValue() As Boolean
Get
Return Not Me._isNull
End Get
End Property
''' <summary>
''' Gets a value indicating whether this instance is null.
''' </summary>
''' <value><c>true</c> if this instance is null; otherwise, false.</value>
Public ReadOnly Property IsNull() As Boolean Implements System.Data.SqlTypes.INullable.IsNull
Get
Return Me._isNull
End Get
End Property
#End Region
#Region "Methods"
''' <summary>
''' Sets the internal is-null flag.
''' </summary>
''' <param name="value">if set to <c>true</c> [value].
Protected Sub SetIsNull(ByVal value As Boolean)
Me._isNull = value
End Sub
#End Region
End Class
There is a private boolean field
_isNull which will hold the nullable state of the object. There are two properties that refer to this;
IsNull and
HasValue. These are in essence opposites of each other but have both been implemented to make the code more
English when using. The
IsNull property is implementation required from the "System.Data.SqlTypes.INullable" interface that the class is going to implement.
There is one method, The
SetIsNull which sets the object state Null and can be called from inside any classes that inherit from this object.
Nullable DateTime Object
The nullable DateTime object will inherit from the
NullableBaseObject. There will be a single private field
_internalDate of type
System.DateTime. This will hold our
DateTime information when the object is not
Null. This will be accessed by all internal code using a private property
InternalDate. Unlike the
System.DateTime which is
Structure, I want to be able to set this object to
Nothing, so I will use a
Class, not a
Structure.
Option Explicit On
Option Strict On
''' <summary>
''' Represents nullable an instance in time, typically represented as a date and time.
''' </summary>
<serializable()> _
Public Class DateTimeNull
Inherits NullableBaseObject
#Region "Declarations"
Private _internalDate As System.DateTime
#End Region
#Region "Properties"
''' <summary>
''' Privately gets or sets the internal date. When set IsNull property is set to false.
''' </summary>
''' <value>The internal date.</value>
Private Property InternalDate() As System.DateTime
Get
Return Me._internalDate
End Get
Set(ByVal value As System.DateTime)
Me._internalDate = value
If Me.IsNull Then
Me.SetIsNull(False)
End If
End Set
End Property
#End Region
End ClassWe will provide an overridden ToString() method which will return the default ToString() value for either the System.DateTime object or the System.DBNull.Value, depending if our object is in a Null state or not.
#Region "Methods"
''' <summary>
''' Converts the value of this instance to its equivalent string representation.
''' </summary>
''' <returns>
''' A <see cref="System.String"> that represents this instance.
''' </returns>
Public Overrides Function ToString() As String
If Me.HasValue Then
Return Me.InternalDate.ToString
Else
Return DBNull.Value.ToString
End If
End Function
#End RegionWe will now look at the constructors we wish to use to allow creation of our object. First we'll look at the default constructor.This constructor initialises the base object, and then calls the base object's
SetIsNull() method to set a null state.
#Region "Constructors"
''' <summary>
''' Initializes a new instance of the class, with IsNull = true.
''' </summary>
Public Sub New()
MyBase.New()
Mybase.SetIsNull(True)
End Sub
#End RegionIn
Part 2, we'll look at adding more constructors that we will need when creating casting operators later.