Como faço para usar DateTime.ExperimenteParse com um Nullable <DateTime>?

115

Eu quero usar o método DateTime.ExperimenteParse para obter o valor de data e hora de uma string em um Nullable. Mas quando eu tento isso:

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

o compilador me diz

argumento 'out' não é classificado como uma variável

Não tenho certeza do que preciso fazer aqui. Eu também tentei:

out (DateTime)d.Value 

e isso também não funciona. Alguma ideia?

Brian Sullivan
fonte

Respostas:

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

(Pode haver soluções mais elegantes, mas por que você simplesmente não faz algo como acima?)

Jason Kealey
fonte
3
Você está certo, eu estava procurando mais de uma linha para fazer isso, mas suponho que isso vai servir. Não gosto de criar essa variável temporária, parece confuso. : - / Parece que este cenário deve ser melhor suportado.
Brian Sullivan,
1
veja a sugestão de Binary Worrier para psuedo-inline isso em um método de extensão.
David Alpert,
4
Por que você está transmitindo um DateTime para um DateTime? Você não precisa refazer o d2 antes de passá-lo para o TryParse.
Aaron Powell
@Slace - Eu atualizei a resposta para incorporar sua sugestão.
Drew Noakes
@Jason Kealey Espero que isso já tenha sido introduzido no VS2012, caso contrário, terei que continuar usando este bom código.
Pimenta
161

Como diz Jason, você pode criar uma variável do tipo certo e passar isso. Você pode querer encapsulá-lo em seu próprio método:

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

... ou se você gosta do operador condicional:

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

Ou em C # 7:

public static DateTime? TryParse(string text) =>
    DateTime.TryParse(text, out var date) ? date : (DateTime?) null;
Jon Skeet
fonte
5
Eu provavelmente não deveria discutir com o Skeet, mas ... você deve chamar seu método Parse, já que eu esperaria que um método chamado TryParse seguisse a convenção TryParse e retornasse um booleano. ;-)
Myster
@Myster: Bem, em nenhum dos casos ele segue exatamente a convenção existente - aqueles que costumavam apenas Parseesperariam que ele retornasse DateTimee gerasse uma exceção em caso de falha, certo? Mas sim, você pode fazer o que quiser ... e no Tempo de Noda, nomeei os métodos relevantes Parse.
Jon Skeet
1
A elsepalavra-chave é desnecessária (em seu primeiro exemplo), pois o ponto final do ifbloco nunca pode ser alcançado.
Jeppe Stig Nielsen
1
@JeppeStigNielsen: Sim, é desnecessário - mas pode ser estilisticamente preferível para simetria. É apenas uma preferência pessoal (e também não sou consistente ...)
Jon Skeet
3
@Kiquenet: o uso de else deixa mais claro que um ou outro caminho será percorrido e ambos retornarão. Sou contra código aninhado massivamente, mas neste caso não é realmente um problema IMO.
Jon Skeet de
20

Aqui está uma edição ligeiramente concisa do que Jason sugeriu:

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

fonte
18

Você não pode porque Nullable<DateTime>é um tipo diferente de DateTime. Você precisa escrever sua própria função para fazer isso,

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

Espero que isto ajude :)

EDITAR: Removido o método de extensão (obviamente) testado de maneira inadequada, porque (como apontado por alguns hoor ruins) os métodos de extensão que tentam alterar o parâmetro "this" não funcionarão com Tipos de valor.

PS O Bad Hoor em questão é um velho amigo :)

Preocupante binário
fonte
Você não quer iniciar a data [já que você está usando como um parâmetro de saída] OK, vou parar de ser exigente!
Ruben Bartelink
Não tenho um compilador comigo, mas como DateTime é um tipo de valor, o método de extensão def compila?
Ruben Bartelink
O resultado não volta a menos que você o faça - [TestFixture] public class WhenExtending {[Test] public void TryParseShouldWork () {DateTime? x = nulo; var res = Externders.ExperimenteParse (x, "01/01/1990"); Assert.IsTrue (res)
Ruben Bartelink

; Assert.That (x! = Null); }} falha na Assert. Isso, ou seja, o resultado não é modificado porque DateTime é um tipo de valor (o que é sempre uma boa questão de eliminação nas telas de telefone: D)
Ruben Bartelink
(óbvio que o primeiro (sem extensão) funcionará, mas deve estar fora, não ref - e você deve anular o resultado se ele não se ajustar às APIs TryXXX em geral - Tenho certeza que o FDG menciona isso. Cara, estou Eu exigente!
Ruben Bartelink
4

Que tal criar um método de extensão?

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
fonte
2
Qual é o primeiro parâmetro,, dateTimepara? Nunca é usado.
Mike Zboray
1
@mikez - é assim que os métodos de extensão funcionam, é usado pelo compilador para saber que deve ser um método de extensão.
Erik Funkenbusch
3
@MystereMan Eu sei o que é um método de extensão. Uma assinatura mais apropriada para um método de extensão seria DateTime? TryParse(this string dateString). Essa implementação é simplesmente bizarra.
Mike Zboray
3
@mikez - então por que você perguntou para que era? Por que poluir o namespace da string quando você só precisa dele para datetime? O objetivo é fornecer um análogo a DateTime.ExperimenteParse que é DateTime?. TryParse
Erik Funkenbusch
1
@ErikFunkenbusch Este método de extensão não permitirá uma sintaxe de chamada como (DateTime?).TryParse( ... )ou Nullable<DateTime>.TryParse( ... ). Então mike z está certo, essa é uma assinatura boba para o método.
Jeppe Stig Nielsen
1

Não vejo por que a Microsoft não lidou com isso. Um pequeno método utilitário inteligente para lidar com isso (tive o problema com int, mas substituir int por DateTime terá o mesmo efeito, pode ser ...

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

Este é o revestimento que você está procurando:

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

Se quiser torná-lo um método de pseudo-extensão TryParse adequado, você pode fazer isso:

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
fonte
@robnick Como isso é diferente do que eu disse?
cpcolella
1
Ignore meu comentário anterior (eu votei sua solução!), Para o C # mais recente, precisei lançar o null: DateTime? d = DateTime.ExperimenteParse (blah, out DateTime dt)? dt: (DateTime?) null;
robnick
1

Aqui está uma solução de linha única:

DateTime? d = DateTime.TryParse("text", out DateTime parseDate) ? parseDate : (DateTime?)null;
usuário1267054
fonte
-3

Como alternativa, se você não estiver preocupado com a possível exceção gerada, pode alterar o TryParse para o Parse:

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

Embora também não haja um booleano indicando o sucesso, pode ser prático em algumas situações em que você sabe que o texto de entrada sempre será válido.

Monsieurgutix
fonte