Comment utiliser DateTime.TryParse avec un <DateTime> Nullable?

115

Je souhaite utiliser la méthode DateTime.TryParse pour obtenir la valeur datetime d'une chaîne dans un Nullable. Mais quand j'essaye ceci:

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

le compilateur me dit

L'argument 'out' n'est pas classé comme une variable

Je ne sais pas ce que je dois faire ici. J'ai aussi essayé:

out (DateTime)d.Value 

et cela ne fonctionne pas non plus. Des idées?

Brian Sullivan
la source

Réponses:

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

(Il peut y avoir des solutions plus élégantes, mais pourquoi ne faites-vous pas simplement quelque chose comme ci-dessus?)

Jason Kealey
la source
3
Vous avez raison, je cherchais plus d'un one-liner pour le faire, mais je suppose que cela fera l'affaire. Je n'aime pas créer cette variable de température, cela semble compliqué. : - / On dirait que ce scénario devrait être mieux pris en charge.
Brian Sullivan
1
voir la suggestion de Binary Worrier de psuedo-inline dans une méthode d'extension.
David Alpert
4
Pourquoi convertissez-vous un DateTime en DateTime? Vous n'avez pas besoin de recaser d2 avant de le passer dans TryParse.
Aaron Powell
@Slace - J'ai mis à jour la réponse pour intégrer votre suggestion.
Drew Noakes
@Jason Kealey J'espère que cela est déjà introduit dans VS2012, sinon je devrai continuer à utiliser ce bon morceau de code.
Pimenta
161

Comme le dit Jason, vous pouvez créer une variable du bon type et la transmettre. Vous voudrez peut-être l'encapsuler dans votre propre méthode:

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

... ou si vous aimez l'opérateur conditionnel:

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

Ou en C # 7:

public static DateTime? TryParse(string text) =>
    DateTime.TryParse(text, out var date) ? date : (DateTime?) null;
Jon Skeet
la source
5
Je ne devrais probablement pas discuter avec The Skeet, mais ... vous devriez appeler votre méthode Parse, car je m'attendrais à ce qu'une méthode appelée TryParse suive la convention TryParse et renvoie un booléen. ;-)
Myster
@Myster: Eh bien, dans aucun des cas, il ne suit la convention existante exacte - ceux qui étaient habitués Parses'attendraient simplement à ce qu'il revienne DateTimeet lève une exception en cas d'échec, non? Mais oui, vous pouvez faire ce que vous voulez ... et dans Noda Time, j'ai nommé les méthodes appropriées à la Parseplace.
Jon Skeet
1
Le elsemot-clé est inutile (dans votre premier exemple) car le point final du ifbloc ne peut jamais être atteint.
Jeppe Stig Nielsen
1
@JeppeStigNielsen: Oui, c'est inutile - mais cela peut être préférable d'un point de vue stylistique pour la symétrie. C'est juste une préférence personnelle (et je ne suis pas cohérent non plus ...)
Jon Skeet
3
@Kiquenet: utiliser else indique plus clairement que l'un ou l'autre chemin sera emprunté, et les deux reviennent. Je suis contre le code massivement imbriqué, mais dans ce cas ce n'est vraiment pas un problème IMO.
Jon Skeet
20

Voici une édition légèrement concise de ce que Jason a suggéré:

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

la source
18

Vous ne pouvez pas parce que Nullable<DateTime>c'est un type différent de DateTime. Vous devez écrire votre propre fonction pour le faire,

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

J'espère que cela t'aides :)

EDIT: Suppression de la méthode d'extension (évidemment) mal testée, car (comme souligné par certains mauvais hoor) les méthodes d'extension qui tentent de modifier le paramètre "this" ne fonctionneront pas avec les types de valeur.

PS The Bad Hoor en question est un vieil ami :)

Binaire Worrier
la source
Tu ne veux pas initier la date [car tu l'utilises comme paramètre de sortie] OK, je vais arrêter d'être difficile!
Ruben Bartelink
Je n'ai pas de compilateur sur moi, mais comme DateTime est un type valeur, la méthode d'extension def compile-t-elle?
Ruben Bartelink
Le résultat ne revient que si vous le faites - [TestFixture] public class WhenExtending {[Test] public void TryParseShouldWork () {DateTime? x = nul; var res = Externders.TryParse (x, "1/1/1990"); Assert.IsTrue (res)
Ruben Bartelink

; Assert.That (x! = Null); }} échoue sur l'Assert.That, c'est-à-dire que le résultat n'est pas modifié car DateTime est un type de valeur (qui est toujours une belle question d'élimination sur les écrans de téléphone: D)
Ruben Bartelink
(bien sûr, le premier (sans extension) fonctionnera, mais il devrait être out, pas ref - et vous devriez annuler le résultat s'il ne s'intègre pas avec les API TryXXX en général - à peu près sûr que FDG le mentionne. Man, am Je suis difficile!
Ruben Bartelink
4

Qu'en est-il de la création d'une méthode d'extension?

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
la source
2
Quel est ce premier paramètre dateTime, pour? Il n'est jamais utilisé.
Mike Zboray
1
@mikez - c'est ainsi que fonctionnent les méthodes d'extension, il est utilisé par le compilateur pour savoir qu'il devrait s'agir d'une méthode d'extension.
Erik Funkenbusch
3
@MystereMan Je sais ce qu'est une méthode d'extension. Une signature plus appropriée pour une méthode d'extension serait DateTime? TryParse(this string dateString). Cette implémentation est tout simplement bizarre.
Mike Zboray
3
@mikez - alors pourquoi avez-vous demandé à quoi cela servait? Pourquoi polluer l'espace de noms de chaîne alors que vous n'en avez besoin que pour datetime? Le but est de fournir un analogue à DateTime.TryParse qui est DateTime? .TryParse
Erik Funkenbusch
1
@ErikFunkenbusch Cette méthode d'extension n'autorisera pas une syntaxe d'appel comme (DateTime?).TryParse( ... )ou Nullable<DateTime>.TryParse( ... ). Donc mike z a raison, c'est une signature idiote pour la méthode.
Jeppe Stig Nielsen
1

Je ne vois pas pourquoi Microsoft n'a pas géré cela. Une petite méthode utilitaire intelligente pour gérer cela (j'ai eu le problème avec int, mais remplacer int par DateTime aura le même effet, pourrait être .....

    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
la source
1

C'est la seule doublure que vous recherchez pour:

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

Si vous voulez en faire une méthode de pseudo-extension TryParse appropriée, vous pouvez le faire:

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
la source
@robnick En quoi est-ce différent de ce que j'ai dit?
cpcolella
1
Ignorez mon commentaire précédent (j'ai voté pour votre solution!), Pour le dernier C # dont j'avais besoin pour convertir le null: DateTime? d = DateTime.TryParse (blah, out DateTime dt)? dt: (DateTime?) null;
robnick
1

Voici une solution sur une seule ligne:

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

Sinon, si vous n'êtes pas concerné par la possible exception déclenchée, vous pouvez modifier TryParse pour Parse:

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

Bien qu'il n'y ait pas non plus de booléen indiquant le succès, cela peut être pratique dans certaines situations où vous savez que le texte d'entrée sera toujours valide.

monsieurgutix
la source