Dlaczego nie mogę sprawdzić, czy „DateTime” to „Nothing”?

81

Czy w VB.NET można ustawić DateTimezmienną jako „nieustawiona”? I dlaczego jest to możliwe, aby ustawić DateTimeTO Nothing, ale nie można sprawdzić, czy jest Nothing? Na przykład:

Dim d As DateTime = Nothing
Dim boolNotSet As Boolean = d Is Nothing 

Druga instrukcja generuje ten błąd:

'Is' operator does not accept operands of type 'Date'. Operands must be reference or
nullable types.
Muleskinner
źródło
1
Oprócz poniższej odpowiedzi Johna Ganta możesz również sprawdzić, czy zmienna datetime = Nothing (zwróć uwagę na = zamiast „is”).
DCNYAM
Dzięki, używając Dim boolNotSet As Boolean = d = Nic nie wydaje się teraz najprostszym rozwiązaniem. Ciekawe z obsadą Nullable, której nigdy wcześniej nie widziałem
Muleskinner
@Chris - Myślę, że używa VB
Karthik Ratnam
@Karthik Ratnam, tak, jest, ale sprowadza się to do tego samego, a odpowiedź @Marc Gravell obejmuje wszystkie punkty.
Chris Haas,
1
@NYSystemsAnalyst: według Nothing (Visual Basic) używanie = Nothinglub <> Nothingnie jest dobrą praktyką: „Podczas sprawdzania, czy zmienna odwołania (lub typu wartości null ) ma wartość null , nie używaj = Nothinglub <> Nothing. Zawsze używaj Is Nothinglub IsNot Nothing.”
DavidRR

Odpowiedzi:

140

Jest to jedno z największych źródeł nieporozumień z VB.Net, IMO.

Nothingw VB.Net jest odpowiednikiem default(T)w C #: wartość domyślna dla danego typu.

  • W przypadku typów wartości jest to zasadniczo odpowiednik „zera”: 0for Integer, Falsefor Boolean, DateTime.MinValuefor DateTime, ...
  • W przypadku typów referencyjnych jest to nullwartość (odwołanie, które odwołuje się do niczego).

Instrukcja d Is Nothingjest zatem równoważna z d Is DateTime.MinValue, która oczywiście nie jest kompilowana.

Rozwiązania: jak powiedzieli inni

  • Albo użyj DateTime?(tj Nullable(Of DateTime).). To jest moje preferowane rozwiązanie.
  • Lub użyj d = DateTime.MinValuelub równoważnied = Nothing

W kontekście oryginalnego kodu możesz użyć:

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

Bardziej wyczerpujące wyjaśnienie można znaleźć na blogu Anthony'ego D. Greena

jeroenh
źródło
1
Dzięki za wyjaśnienie. Warto zauważyć, że isNothing (d) nie działa, ale d = Nic nie działa!
phn
12

DateTime jest typem wartości, dlatego nie może mieć wartości null. Możesz sprawdzić, czy jest równy DateTime.MinValue, lub możesz użyć Nullable(Of DateTime)zamiast tego.

VB czasami „pomocnie” sprawia, że ​​myślisz, że robi coś, czym nie jest. Kiedy pozwala ustawić datę na Nothing, tak naprawdę ustawia ją na inną wartość, na przykład MinValue.

Zobacz to pytanie, aby uzyskać obszerną dyskusję na temat typów wartości i typów referencyjnych.

John M Gant
źródło
4

DateTime jest typem wartości , co oznacza, że ​​zawsze ma jakąś wartość.

Jest jak liczba całkowita - może wynosić 0, 1 lub mniej niż zero, ale nigdy nie może oznaczać „nic”.

Jeśli chcesz DateTime, który może przyjąć wartość Nothing, użyj wartości Nullable DateTime.

Ser
źródło
4

Kilka przykładów pracy z DateTimewartościami dopuszczającymi wartość null .

(Zobacz Typy wartości null (Visual Basic), aby uzyskać więcej informacji).

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

Ponadto, jak sprawdzić, czy zmienna jest null (z Nothing (Visual Basic) ):

Podczas sprawdzania, czy zmienna odwołania (lub typu wartości null ) ma wartość null , nie używaj = Nothinglub <> Nothing. Zawsze używaj Is Nothinglub IsNot Nothing.
DavidRR
źródło
1

W każdym języku programowania zachowaj ostrożność podczas używania wartości Null. Powyższy przykład pokazuje inny problem. Jeśli używasz typu Nullable, oznacza to, że zmienne, których wystąpienie pochodzi z tego typu, mogą zawierać wartość System.DBNull.Value; nie to, że zmienił interpretację ustawienia wartości na domyślną za pomocą "= Nothing" lub że obiekt wartości może teraz obsługiwać odwołanie o wartości null. Tylko ostrzeżenie ... miłego kodowania!

Możesz utworzyć oddzielną klasę zawierającą typ wartości. Obiekt utworzony z takiej klasy byłby typem referencyjnym, któremu można by przypisać Nothing. Przykład:

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

Koniec klasy

'w głównym ():

        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

Następnie możesz wybrać i wybrać overridables, aby zrobić to, czego potrzebujesz. Dużo pracy - ale jeśli naprawdę tego potrzebujesz, możesz to zrobić.

sscheider
źródło
1

Możesz również użyć poniżej, aby po prostu sprawdzić:

If startDate <> Nothing Then
your logic
End If

Sprawdza, czy zmienna startDate typu danych DateTime ma wartość NULL, czy nie.

Mahavirsinh Padhiyar
źródło
1

Możesz to sprawdzić jak poniżej:

if varDate = "#01/01/0001#" then
       '  blank date. do something.
else
       ' Date is not blank. Do some other thing
end if
Sukhi
źródło
0

Sposobem na obejście tego byłoby użycie zamiast tego typu danych Object:

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

Następnie możesz ustawić datę na inną niż ta:

MyDate = Nothing
Dim theDate As Date = MyDate
If theDate = Nothing Then
    'date is nothing
End If
George Filippakos
źródło