Why can't I check if a 'DateTime' is 'Nothing'?
سؤال
In VB.NET, is there a way to set a DateTime
variable to "not set"? And why is it possible to set a DateTime
to Nothing
, but not possible to check if it is Nothing
? For example:
Dim d As DateTime = Nothing
Dim boolNotSet As Boolean = d Is Nothing
The second statement throws this error:
'Is' operator does not accept operands of type 'Date'. Operands must be reference or
nullable types.
المحلول
This is one of the biggest sources of confusion with VB.Net, IMO.
Nothing
in VB.Net is the equivalent of default(T)
in C#: the default value for the given type.
- For value types, this is essentially the equivalent of 'zero':
0
forInteger
,False
forBoolean
,DateTime.MinValue
forDateTime
, ... - For reference types, it is the
null
value (a reference that refers to, well, nothing).
The statement d Is Nothing
is therefore equivalent to d Is DateTime.MinValue
, which obviously does not compile.
Solutions: as others have said
- Either use
DateTime?
(i.e.Nullable(Of DateTime)
). This is my preferred solution. - Or use
d = DateTime.MinValue
or equivalentlyd = Nothing
In the context of the original code, you could use:
Dim d As DateTime? = Nothing
Dim boolNotSet As Boolean = d.HasValue
A more comprehensive explanation can be found on Anthony D. Green's blog
نصائح أخرى
DateTime is a value type, which is why it can't be null. You can check for it to be equal to DateTime.MinValue
, or you can use Nullable(Of DateTime)
instead.
VB sometimes "helpfully" makes you think it's doing something it's not. When it lets you set a Date to Nothing, it's really setting it to some other value, maybe MinValue.
See this question for an extensive discussion of value types vs. reference types.
DateTime is a value type, which means it always has some value.
It's like an integer - it can be 0, or 1, or less than zero, but it can never be "nothing".
If you want a DateTime that can take the value Nothing, use a Nullable DateTime.
Some examples on working with nullable DateTime
values.
(See Nullable Value Types (Visual Basic) for more.)
'
' An ordinary DateTime declaration. It is *not* nullable. Setting it to
' 'Nothing' actually results in a non-null value.
'
Dim d1 As DateTime = Nothing
Console.WriteLine(String.Format("d1 = [{0}]\n", d1))
' Output: d1 = [1/1/0001 12:00:00 AM]
' Console.WriteLine(String.Format("d1 is Nothing? [{0}]\n", (d1 Is Nothing)))
'
' Compilation error on above expression '(d1 Is Nothing)':
'
' 'Is' operator does not accept operands of type 'Date'.
' Operands must be reference or nullable types.
'
' Three different but equivalent ways to declare a DateTime
' nullable:
'
Dim d2? As DateTime = Nothing
Console.WriteLine(String.Format("d2 = [{0}][{1}]\n", d2, (d2 Is Nothing)))
' Output: d2 = [][True]
Dim d3 As DateTime? = Nothing
Console.WriteLine(String.Format("d3 = [{0}][{1}]\n", d3, (d3 Is Nothing)))
' Output: d3 = [][True]
Dim d4 As Nullable(Of DateTime) = Nothing
Console.WriteLine(String.Format("d4 = [{0}][{1}]\n", d4, (d4 Is Nothing)))
' Output: d4 = [][True]
Also, on how to check whether a variable is null (from Nothing (Visual Basic)):
When checking whether a reference (or nullable value type) variable is null, do not use= Nothing
or<> Nothing
. Always useIs Nothing
orIsNot Nothing
.
In any programming language, be careful when using Nulls. The example above shows another issue. If you use a type of Nullable, that means that the variables instantiated from that type can hold the value System.DBNull.Value; not that it has changed the interpretation of setting the value to default using "= Nothing" or that the Object of the value can now support a null reference. Just a warning... happy coding!
You could create a separate class containing a value type. An object created from such a class would be a reference type, which could be assigned Nothing. An example:
Public Class DateTimeNullable
Private _value As DateTime
'properties
Public Property Value() As DateTime
Get
Return _value
End Get
Set(ByVal value As DateTime)
_value = value
End Set
End Property
'constructors
Public Sub New()
Value = DateTime.MinValue
End Sub
Public Sub New(ByVal dt As DateTime)
Value = dt
End Sub
'overridables
Public Overrides Function ToString() As String
Return Value.ToString()
End Function
End Class
'in Main():
Dim dtn As DateTimeNullable = Nothing
Dim strTest1 As String = "Falied"
Dim strTest2 As String = "Failed"
If dtn Is Nothing Then strTest1 = "Succeeded"
dtn = New DateTimeNullable(DateTime.Now)
If dtn Is Nothing Then strTest2 = "Succeeded"
Console.WriteLine("test1: " & strTest1)
Console.WriteLine("test2: " & strTest2)
Console.WriteLine(".ToString() = " & dtn.ToString())
Console.WriteLine(".Value.ToString() = " & dtn.Value.ToString())
Console.ReadKey()
' Output:
'test1: Succeeded()
'test2: Failed()
'.ToString() = 4/10/2012 11:28:10 AM
'.Value.ToString() = 4/10/2012 11:28:10 AM
Then you could pick and choose overridables to make it do what you need. Lot of work - but if you really need it, you can do it.
You can also use below just simple to check:
If startDate <> Nothing Then
your logic
End If
It will check that the startDate variable of DateTime datatype is null or not.
You can check this like below :
if varDate = "#01/01/0001#" then
' blank date. do something.
else
' Date is not blank. Do some other thing
end if
A way around this would be to use Object datatype instead:
Private _myDate As Object
Private Property MyDate As Date
Get
If IsNothing(_myDate) Then Return Nothing
Return CDate(_myDate)
End Get
Set(value As Date)
If date = Nothing Then
_myDate = Nothing
Return
End If
_myDate = value
End Set
End Property
Then you can set the date to nothing like so:
MyDate = Nothing
Dim theDate As Date = MyDate
If theDate = Nothing Then
'date is nothing
End If