Jak używać DateTime.TryParse z wartością Nullable <DateTime>?

115

Chcę użyć metody DateTime.TryParse, aby uzyskać wartość daty i godziny w ciągu do wartości Nullable. Ale kiedy próbuję tego:

DateTime? d;
bool success = DateTime.TryParse("some date text", out (DateTime)d);

kompilator mi mówi

Argument „out” nie jest klasyfikowany jako zmienna

Nie wiem, co muszę tutaj zrobić. Próbowałem też:

out (DateTime)d.Value 

i to też nie działa. Jakieś pomysły?

Brian Sullivan
źródło

Odpowiedzi:

123
DateTime? d=null;
DateTime d2;
bool success = DateTime.TryParse("some date text", out d2);
if (success) d=d2;

(Mogą być bardziej eleganckie rozwiązania, ale dlaczego po prostu nie zrobisz czegoś takiego jak powyżej?)

Jason Kealey
źródło
3
Masz rację, szukałem czegoś więcej, żeby to zrobić, ale przypuszczam, że to wystarczy. Nie lubię tworzyć tej zmiennej tymczasowej, czuje się bałagan. : - / Wydaje się, że ten scenariusz powinien być lepiej obsługiwany.
Brian Sullivan
1
zobacz sugestię Binary Worrier, aby psuedo-inline to w metodzie rozszerzenia.
David Alpert,
4
Dlaczego rzutujesz DateTime na DateTime? Nie musisz recasować d2 przed przekazaniem go do TryParse.
Aaron Powell
@Slace - zaktualizowałem odpowiedź, aby uwzględnić Twoją sugestię.
Drew Noakes
@Jason Kealey Mam nadzieję, że jest to już wprowadzone w VS2012, w przeciwnym razie będę musiał nadal używać tego dobrego fragmentu kodu.
Pimenta
161

Jak mówi Jason, możesz stworzyć zmienną odpowiedniego typu i przekazać ją. Możesz chcieć zamknąć go w swojej własnej metodzie:

public static DateTime? TryParse(string text)
{
    DateTime date;
    if (DateTime.TryParse(text, out date))
    {
        return date;
    }
    else
    {
        return null;
    }
}

... lub jeśli podoba ci się operator warunkowy:

public static DateTime? TryParse(string text)
{
    DateTime date;
    return DateTime.TryParse(text, out date) ? date : (DateTime?) null;
}

Lub w C # 7:

public static DateTime? TryParse(string text) =>
    DateTime.TryParse(text, out var date) ? date : (DateTime?) null;
Jon Skeet
źródło
5
Prawdopodobnie nie powinienem kłócić się z The Skeet, ale ... powinieneś wywołać swoją metodę Parse, ponieważ spodziewałbym się, że metoda o nazwie TryParse będzie postępować zgodnie z konwencją TryParse i zwróci wartość logiczną. ;-)
Myster
@Myster: Cóż, w żadnym przypadku nie jest zgodny z dokładną istniejącą konwencją - ci, którzy zwykli po prostu Parseoczekiwać, że powróci DateTimei zgłosi wyjątek w przypadku niepowodzenia, prawda? Ale tak, możesz robić, co chcesz ... aw Czasie Nody Parsezamiast tego wymieniłem odpowiednie metody .
Jon Skeet
1
Słowo elsekluczowe jest niepotrzebne (w Twoim pierwszym przykładzie), ponieważ punkt końcowy ifbloku nigdy nie może zostać osiągnięty.
Jeppe Stig Nielsen
1
@JeppeStigNielsen: Tak, to niepotrzebne - ale może być stylistycznie preferowane dla symetrii. To tylko osobiste preferencje (i też nie jestem konsekwentny ...)
Jon Skeet
3
@Kiquenet: użycie else sprawia, że ​​wyraźniej widać, że jedna lub druga ścieżka zostanie wybrana i obie powrócą. Jestem przeciwnikiem masowo zagnieżdżonego kodu, ale w tym przypadku IMO to naprawdę nie jest problem.
Jon Skeet
20

Oto nieco zwięzłe wydanie tego, co zasugerował Jason:

DateTime? d; DateTime dt;
d = DateTime.TryParse(DateTime.Now.ToString(), out dt)? dt : (DateTime?)null;

źródło
18

Nie możesz, ponieważ Nullable<DateTime>jest to inny typ DateTime. Aby to zrobić, musisz napisać własną funkcję,

public bool TryParse(string text, out Nullable<DateTime> nDate)
{
    DateTime date;
    bool isParsed = DateTime.TryParse(text, out date);
    if (isParsed)
        nDate = new Nullable<DateTime>(date);
    else
        nDate = new Nullable<DateTime>();
    return isParsed;
}

Mam nadzieję że to pomoże :)

EDYCJA: Usunięto (oczywiście) nieprawidłowo przetestowaną metodę rozszerzenia, ponieważ (jak wskazały niektóre złe hoor) metody rozszerzające, które próbują zmienić parametr „this”, nie będą działać z typami wartości.

PS Bad Hoor, o którym mowa, to stary przyjaciel :)

Binary Worrier
źródło
Nie chcesz inicjować daty [ponieważ używasz jej jako parametru wyjścia] OK, przestanę być wybredny!
Ruben Bartelink
Nie mam kompilatora, ale ponieważ DateTime jest typem wartości, czy metoda rozszerzenia def kompiluje się?
Ruben Bartelink
Wynik nie wraca, dopóki go nie zrobisz - [TestFixture] klasa publiczna WhenExtending {[Test] public void TryParseShouldWork () {DateTime? x = null; var res = Externders.TryParse (x, "1/1/1990"); Assert.IsTrue (res)
Ruben Bartelink

; Assert.That (x! = Null); }} kończy się niepowodzeniem na Assert. Oznacza to, że wynik nie jest modyfikowany, ponieważ DateTime jest typem wartości (co jest zawsze miłym pytaniem na ekrany telefonów: D)
Ruben Bartelink
(obv pierwszy (bez rozszerzenia) zadziała, ale powinien być niedostępny, a nie ref - i powinieneś anulować wynik, jeśli nie pasuje do interfejsów API TryXXX w ogóle - Jestem pewien, że FDG o tym wspomina. Człowieku, jestem Jestem wybredny!
Ruben Bartelink
4

A co z tworzeniem metody rozszerzenia?

public static class NullableExtensions
{
    public static bool TryParse(this DateTime? dateTime, string dateString, out DateTime? result)
    {
        DateTime tempDate;
        if(! DateTime.TryParse(dateString,out tempDate))
        {
            result = null;
            return false;
        }

        result = tempDate;
        return true;

    }
}
user2687864
źródło
2
Do czego służy ten pierwszy parametr dateTime? Nigdy nie jest używany.
Mike Zboray
1
@mikez - tak działają metody rozszerzające, kompilator używa go, aby wiedzieć, że powinna to być metoda rozszerzająca.
Erik Funkenbusch
3
@MystereMan Wiem, co to jest metoda rozszerzenia. Bardziej odpowiednią sygnaturą dla metody rozszerzenia byłaby DateTime? TryParse(this string dateString). Ta implementacja jest po prostu dziwna.
Mike Zboray,
3
@mikez - to dlaczego zapytałeś, do czego to służy? Po co zanieczyszczać przestrzeń nazw łańcuchów, skoro jest ona potrzebna tylko dla daty i godziny? Celem jest zapewnienie analogu do DateTime.TryParse, czyli DateTime? .TryParse
Erik Funkenbusch
1
@ErikFunkenbusch Ta metoda rozszerzenia nie zezwala na składnię wywołań, takich jak (DateTime?).TryParse( ... )lub Nullable<DateTime>.TryParse( ... ). Więc mike z ma rację, to głupi podpis metody.
Jeppe Stig Nielsen
1

Nie rozumiem, dlaczego Microsoft tego nie poradził. Sprytna, mała, użyteczna metoda radzenia sobie z tym problemem (miałem problem z int, ale zastąpienie int przez DateTime da ten sam efekt, może być .....

    public static bool NullableValueTryParse(string text, out int? nInt)
    {
        int value;
        if (int.TryParse(text, out value))
        {
            nInt = value;
            return true;
        }
        else
        {
            nInt = null;
            return false;
        }
    }
JStrahl
źródło
1

Oto jedyna wkładka, której szukasz:

DateTime? d = DateTime.TryParse("some date text", out DateTime dt) ? dt : null;

Jeśli chcesz, aby była to właściwa metoda pseudo-rozszerzenia TryParse, możesz to zrobić:

public static bool TryParse(string text, out DateTime? dt)
{
    if (DateTime.TryParse(text, out DateTime date))
    {
        dt = date;
        return true;
    }
    else
    {
        dt = null;
        return false;
    }
}
cpcolella
źródło
@robnick Czym to się różni od tego, co powiedziałem?
cpcolella
1
Zignoruj ​​mój poprzedni komentarz (zagłosowałem za twoim rozwiązaniem!), Dla najnowszego C # musiałem rzucić null: DateTime? d = DateTime.TryParse (blah, out DateTime dt)? dt: (DateTime?) null;
robnick
1

Oto rozwiązanie z jedną linią:

DateTime? d = DateTime.TryParse("text", out DateTime parseDate) ? parseDate : (DateTime?)null;
user1267054
źródło
-3

Alternatywnie, jeśli nie jesteś zaniepokojony możliwym zgłoszonym wyjątkiem, możesz zmienić TryParse dla Parse:

DateTime? d = DateTime.Parse("some valid text");

Chociaż nie będzie również wartości logicznej wskazującej na sukces, może to być praktyczne w niektórych sytuacjach, w których wiesz, że tekst wejściowy zawsze będzie prawidłowy.

monsieurgutix
źródło