为什么我无法检查“DateTime”是否为“Nothing”?

89

在VB.NET中,有没有一种方法可以将DateTime变量设置为“未设置”?为什么可以将DateTime设置为Nothing,但无法检查它是否为Nothing?例如:

Dim d As DateTime = Nothing
Dim boolNotSet As Boolean = d Is Nothing 
第二个语句会抛出此错误:
'Is' operator does not accept operands of type 'Date'. Operands must be reference or
nullable types.

1
除了John Gant在下面的回答之外,您还可以检查datetime变量是否等于Nothing(请注意=而不是“is”)。 - DCNYAM
谢谢,目前看来使用“Dim boolNotSet As Boolean = d = Nothing”似乎是最简单的解决方案。对于可空类型的转换很有趣,以前从未见过。 - Muleskinner
@Karthik Ratnam,是的,但这归根结底是同一件事情,而@Marc Gravell的答案则涵盖了所有要点。 - Chris Haas
1
根据Nothing (Visual Basic),使用= Nothing<> Nothing并不是一个好的做法:“当检查引用(或可空值类型)变量是否为null时,不要使用= Nothing<> Nothing。总是使用Is NothingIsNot Nothing。” - DavidRR
小心使用变量 = nothing,这可能导致 NullReferenceException。 - Maddin
显示剩余6条评论
8个回答

151

在 VB.Net 中,这是我认为最令人困惑的部分之一。

Nothing 在 VB.Net 中并不等同于 C# 中的 default:对于给定类型的默认值。

  • 对于值类型,这基本上相当于 “零”:对于 Integer0,对于 BooleanFalse,对于 DateTimeDateTime.MinValue,等等。
  • 对于引用类型,它是 null 值(引用指向没有任何内容的地方)。

因此,语句 d Is Nothing 相当于 d Is DateTime.MinValue,显然不能编译。

解决方案:

  • 使用 DateTime?(即 Nullable(Of DateTime))。这是我首选的解决方案。
  • 或者使用 d = DateTime.MinValue 或同样地使用 d = Nothing

在原始代码的上下文中,您可以使用:

Dim d As DateTime? = Nothing
Dim boolNotSet As Boolean = Not d.HasValue

更全面的解释可以在Anthony D. Green的博客上找到。


1
谢谢解释。有趣的是,isNothing(d)不起作用,但d = Nothing可以! - phn

16

DateTime是值类型,这就是为什么它不能为null的原因。您可以检查它是否等于DateTime.MinValue,或者您可以使用Nullable(Of DateTime)

VB有时会“友好地”让您认为它正在做一些它实际上没有做的事情。当它允许您将日期设置为Nothing时,它实际上是将其设置为其他一些值,可能是MinValue。

有关值类型与引用类型的广泛讨论,请参见此问题


5

DateTime是一个值类型,这意味着它总是有一些值。

就像整数一样 - 它可以是0,或1,或小于零,但它永远不可能是“无”。

如果你想要一个可以取空值的DateTime,请使用可空的DateTime。


4

一些处理可空DateTime值的示例。

(更多信息请参见Nullable Value Types (Visual Basic)。)

'
' 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]

此外,关于如何检查变量是否为null(来自Nothing (Visual Basic)),请注意:
当检查引用(或可空值类型)变量是否为null时,请不要使用= Nothing<> Nothing。始终使用Is NothingIsNot Nothing

1
您也可以使用以下简单方式进行检查:
If startDate <> Nothing Then
your logic
End If

它将检查DateTime数据类型的startDate变量是否为空。

1
您可以像下面这样检查:

if varDate = "#01/01/0001#" then
       '  blank date. do something.
else
       ' Date is not blank. Do some other thing
end if

1
在任何编程语言中,使用Nulls时要小心。上面的示例显示了另一个问题。如果您使用Nullable类型,那意味着从该类型实例化的变量可以保存System.DBNull.Value值;并不是它已经更改了使用“= Nothing”设置默认值的解释,或者该值的对象现在可以支持空引用。只是一个警告...愉快的编码!
您可以创建一个包含值类型的单独类。从这样的类创建的对象将是引用类型,可以分配为Nothing。例如:
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

结束类

'在主函数中:

        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

然后你可以挑选覆盖方法来让它做你需要的事情。虽然这需要大量努力,但如果你确实需要它,你是可以完成的。


0
一个解决方法是使用对象数据类型而不是原始数据类型:
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

然后您可以将日期设置为无,如下所示:

MyDate = Nothing
Dim theDate As Date = MyDate
If theDate = Nothing Then
    'date is nothing
End If

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接