In VB.NET the following code:
Dim myBool As Boolean = False
Dim myDate As Date? = If(myBool, Date.Today, Nothing)
Console.WriteLine(myDate)
Produces:
1/1/0001 12:00:00 AM
However, if I write this out as:
Dim myBool As Boolean = False
Dim myDate As Date?
If myBool Then
myDate = Date.Today
Else
myDate = Nothing
End If
Console.WriteLine(myDate)
Then it will, as expected, print null/nothing.
What's going on here, and how can I have a one-liner to assign a date or null to a nullable DateTime in VB.NET without it in fact defaulting to 01/01/0001 12:00:00 AM
?
The If(myBool, Date.Today, Nothing)
expression must stand on its own, and is evaluated without any influence at all from the left-hand side of the assignment; it doesn't know it will be assigned to a Nullable DateTime.
It's unfortunate for VB.Net, but when considering Nullable types we must remember these were built thinking first about C#'s concept of null
, which is not the same as Nothing
in VB.Net. Specifically, Nothing
is actually closer to C#'s default(T)
expression (or now just default
).
It's therefore often useful to consider the C# adaption of the code. In this case, the actual direct C# translation of the original line of code looks like this, where null
is never used:
DateTime? myDate = myBool ? DateTime.Today : default;
You'll find this matches the VB.Net behavior you've already observed. So we see the final result of the expression is a standard (not nullable) DateTime
value, where Nothing
is interpreted as the default value for this type (DateTime.MinValue
)... which looks like 1/1/0001 12:00:00 AM
when written to the Console on your system.
It's worth noting the Nothing
expression must also stand on it's own in the If/Else version of the code, again without any regard for the left-hand side of the assignment.
myDate = Nothing
It works as expected this time because now the default
in the C# translation is seen as a reference instead of a value, so the result is a true null
instead of a value-type's non-null default.
But also, this Else
block is not needed, and if completely omitted you'd have the same result.
To create the desired result you can instead do this:
If(myBool, Date.Today, CType(Nothing, DateTime?))
Or this:
If(myBool, Date.Today, New Nullable(Of DateTime))
Alternatively, I might use an extra line:
Dim myBool As Boolean = False
Dim myDate As Date?
If myBool Then myDate = Date.Today
Console.WriteLine(myDate)
One final wrinkle to fully understanding all of this is the If()
for the If(myBool, Date.Today, Nothing)
conditional expression is not a function call. It does have some function semantics, but the If()
here is actually an operator.
This allows the compiler to give it special treatment, so the Nothing
used as the second argument can be evaluated to take the type of the Date.Today
expression into account. Otherwise, each function argument would have to fully resolve independently — without regard for the others — before entering the function, and the Nothing
would still be an un-typed (or Object
) null
reference.