Wie verwende ich DateTime.TryParse mit einer nullbaren <DateTime>?

113

Ich möchte die DateTime.TryParse-Methode verwenden, um den datetime-Wert eines Strings in eine Nullable zu bekommen. Aber wenn ich das versuche:

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

Der Compiler sagt es mir

Das Argument 'out' wird nicht als Variable klassifiziert

Ich bin mir nicht sicher, was ich hier tun muss. Ich habe auch versucht:

out (DateTime)d.Value 

und das funktioniert auch nicht. Irgendwelche Ideen?

Brian Sullivan
quelle

Antworten:

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

(Es gibt vielleicht elegantere Lösungen, aber warum machen Sie nicht einfach etwas wie oben?)

Jason Kealey
quelle
3
Sie haben Recht, ich habe mehr nach einem Einzeiler gesucht, um das zu erledigen, aber ich nehme an, das wird reichen. Mag es nicht, diese temporäre Variable zu erstellen, fühlt sich chaotisch an. : - / Scheint, als sollte dieses Szenario besser unterstützt werden.
Brian Sullivan
1
siehe Binary Worriers Vorschlag, dies in eine Erweiterungsmethode zu integrieren.
David Alpert
4
Warum wandeln Sie eine DateTime in eine DateTime um? Sie müssen d2 nicht erneut eingeben, bevor Sie es an TryParse übergeben.
Aaron Powell
@Slace - Ich habe die Antwort aktualisiert, um Ihren Vorschlag aufzunehmen.
Drew Noakes
@ Jason Kealey Ich hoffe, dass dies bereits in VS2012 eingeführt wurde, sonst muss ich diesen guten Code weiterhin verwenden.
Pimenta
161

Wie Jason sagt, können Sie eine Variable des richtigen Typs erstellen und diese übergeben. Möglicherweise möchten Sie es in Ihrer eigenen Methode kapseln:

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

... oder wenn Ihnen der bedingte Operator gefällt:

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

Oder in C # 7:

public static DateTime? TryParse(string text) =>
    DateTime.TryParse(text, out var date) ? date : (DateTime?) null;
Jon Skeet
quelle
5
Ich sollte wahrscheinlich nicht mit The Skeet streiten, aber ... Sie sollten Ihre Methode Parse aufrufen, da ich erwarten würde, dass eine Methode namens TryParse der TryParse-Konvention folgt und einen Booleschen Wert zurückgibt. ;-)
Myster
@Myster: Nun, in keinem Fall folgt es der exakten bestehenden Konvention - diejenigen, die früher nur Parseerwartet hatten, dass es zurückkehrt DateTimeund eine Ausnahme bei einem Fehler auslöst , oder? Aber ja, Sie können tun, was Sie wollen ... und in Noda Time habe ich Parsestattdessen die relevanten Methoden benannt .
Jon Skeet
1
Das elseSchlüsselwort ist (in Ihrem ersten Beispiel) nicht erforderlich, da der Endpunkt des ifBlocks niemals erreicht werden kann.
Jeppe Stig Nielsen
1
@JeppeStigNielsen: Ja, das ist unnötig - aber aus Symmetriegründen mag es stilistisch vorzuziehen sein. Es ist nur eine persönliche Präferenz (und ich bin auch nicht konsequent ...)
Jon Skeet
3
@Kiquenet: Wenn Sie else verwenden, wird klarer, dass der eine oder andere Pfad eingeschlagen wird und beide zurückkehren. Ich bin gegen massiv verschachtelten Code, aber in diesem Fall ist es IMO wirklich kein Problem.
Jon Skeet
20

Hier ist eine leicht prägnante Ausgabe dessen, was Jason vorgeschlagen hat:

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

quelle
18

Sie können nicht, weil Nullable<DateTime>es sich um einen anderen Typ handelt DateTime. Sie müssen Ihre eigene Funktion schreiben, um es zu tun,

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;
}

Hoffe das hilft :)

BEARBEITEN: Die (offensichtlich) nicht ordnungsgemäß getestete Erweiterungsmethode wurde entfernt, da Erweiterungsmethoden, die versuchen, den Parameter "this" zu ändern, mit Werttypen nicht funktionieren.

PS Das fragliche Bad Hoor ist ein alter Freund :)

Binärer Worrier
quelle
Du willst das Datum nicht einleiten [da du es als Out-Parameter verwendest] OK, ich werde aufhören, wählerisch zu sein!
Ruben Bartelink
Ich habe keinen Compiler, aber da DateTime ein Werttyp ist, wird die Erweiterungsmethode def kompiliert?
Ruben Bartelink
Das Ergebnis wird erst wieder angezeigt, wenn Sie es erkannt haben - öffentliche Klasse [TestFixture] 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); }} schlägt auf dem Assert fehl. Das heißt, das Ergebnis wird nicht geändert, da DateTime ein Werttyp ist (was auf Telefonbildschirmen immer eine nette Frage ist: D)
Ruben Bartelink
(obv die erste (keine Erweiterung) wird funktionieren, aber es sollte out sein, nicht ref - und Sie sollten das Ergebnis auf Null setzen, wenn es im Allgemeinen nicht in TryXXX-APIs passt - Ziemlich sicher, dass FDG dies erwähnt Ich wählerisch!
Ruben Bartelink
4

Was ist mit dem Erstellen einer Erweiterungsmethode?

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
quelle
2
Wofür ist dieser erste Parameter dateTime? Es wird nie benutzt.
Mike Zboray
1
@mikez - so funktionieren Erweiterungsmethoden. Der Compiler weiß, dass es sich um eine Erweiterungsmethode handeln sollte.
Erik Funkenbusch
3
@MystereMan Ich weiß, was eine Erweiterungsmethode ist. Eine geeignetere Signatur für eine Erweiterungsmethode wäre DateTime? TryParse(this string dateString). Diese Implementierung ist nur bizarr.
Mike Zboray
3
@mikez - warum hast du dann gefragt, wofür es ist? Warum den String-Namespace verschmutzen, wenn Sie ihn nur für datetime benötigen? Der Zweck ist es, ein Analogon zu DateTime.TryParse bereitzustellen, das DateTime ist? .TryParse
Erik Funkenbusch
1
@ErikFunkenbusch Diese Erweiterung Methode wird nicht einen Anruf Syntax wie lassen (DateTime?).TryParse( ... )oder Nullable<DateTime>.TryParse( ... ). Also ist Mike Z richtig, das ist eine dumme Signatur für die Methode.
Jeppe Stig Nielsen
1

Ich verstehe nicht, warum Microsoft damit nicht umgegangen ist. Eine clevere kleine Dienstprogrammmethode, um damit umzugehen (ich hatte das Problem mit int, aber das Ersetzen von int durch DateTime wird den gleichen Effekt haben, könnte sein .....

    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
quelle
1

Dies ist der einzige Liner, für den Sie suchen:

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

Wenn Sie es zu einer geeigneten TryParse-Pseudoerweiterungsmethode machen möchten, können Sie dies tun:

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
quelle
@robnick Wie unterscheidet sich das von dem, was ich gesagt habe?
cpcolella
1
Ignoriere meinen vorherigen Kommentar (ich habe deine Lösung positiv bewertet!), Für das neueste C # musste ich die Null setzen: DateTime? d = DateTime.TryParse (bla, out DateTime dt)? dt: (DateTime?) null;
Robnick
1

Hier ist eine einzeilige Lösung:

DateTime? d = DateTime.TryParse("text", out DateTime parseDate) ? parseDate : (DateTime?)null;
user1267054
quelle
-3

Wenn Sie sich nicht mit der möglichen Ausnahme befassen, können Sie alternativ TryParse for Parse ändern:

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

Obwohl es auch keinen Booleschen Wert gibt, der den Erfolg anzeigt, kann dies in einigen Situationen praktisch sein, in denen Sie wissen, dass der Eingabetext immer gültig ist.

Monsieurgutix
quelle