Как использовать DateTime.TryParse с Nullable <DateTime>?

116

Я хочу использовать метод DateTime.TryParse, чтобы получить значение datetime строки в Nullable. Но когда я пробую это:

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

компилятор говорит мне

аргумент out не классифицируется как переменная

Не уверен, что мне здесь нужно делать. Я также пробовал:

out (DateTime)d.Value 

и это тоже не работает. Любые идеи?

Брайан Салливан
источник

Ответы:

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

(Могут быть более элегантные решения, но почему бы вам просто не сделать что-то, как указано выше?)

Джейсон Кили
источник
3
Вы правы, я искал больше однострочного, чтобы сделать это, но я полагаю, что это сойдет. Не люблю создавать эту временную переменную, кажется беспорядочным. : - / Похоже, этот сценарий лучше поддерживать.
Брайан Салливан,
1
см. предложение Binary Worrier псевдо-встроить это в метод расширения.
Дэвид Алперт,
4
Почему вы приводите DateTime к DateTime? Вам не нужно повторно использовать d2 перед его передачей в TryParse.
Аарон Пауэлл,
@Slace - Я обновил ответ, чтобы включить ваше предложение.
Дрю Ноукс
@Jason Kealey Я надеюсь, что это уже введено в VS2012, иначе мне придется продолжать использовать этот хороший фрагмент кода.
Pimenta
161

Как говорит Джейсон, вы можете создать переменную правильного типа и передать ее. Возможно, вы захотите инкапсулировать его в свой собственный метод:

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

... или если вам нравится условный оператор:

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

Или в C # 7:

public static DateTime? TryParse(string text) =>
    DateTime.TryParse(text, out var date) ? date : (DateTime?) null;
Джон Скит
источник
5
Я, вероятно, не должен спорить с The Skeet, но ... вы должны вызвать свой метод Parse, поскольку я ожидаю, что метод с именем TryParse будет следовать соглашению TryParse и возвращать логическое значение. ;-)
Myster
@Myster: Ну, в любом случае он не следует в точности существующим соглашениям - те, которые раньше просто Parse ожидали, что он вернется DateTimeи выдаст исключение в случае неудачи, верно? Но да, вы можете делать все, что хотите ... и в Noda Time Parseвместо этого я назвал соответствующие методы .
Джон Скит,
1
В elseКлючевое слово не является необходимым (в первом примере) , так как оконечная часть ifблока не может быть достигнута.
Йеппе Стиг Нильсен
1
@JeppeStigNielsen: Да, в этом нет необходимости, но это может быть стилистически предпочтительнее для симметрии. Это просто личное предпочтение (и я тоже не согласен ...)
Джон Скит
3
@Kiquenet: использование else делает более ясным, что будет выбран тот или иной путь, и оба вернутся. Я против массового вложенного кода, но в данном случае это не проблема, ИМО.
Джон Скит
21

Вот немного сжатое издание того, что предложил Джейсон:

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

источник
18

Вы не можете, потому что Nullable<DateTime>это другой тип DateTime. Для этого вам нужно написать свою собственную функцию,

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

Надеюсь это поможет :)

РЕДАКТИРОВАТЬ: удален (очевидно) неправильно протестированный метод расширения, потому что (как указано в некоторых плохих словах) методы расширения, которые пытаются изменить параметр «этот», не будут работать с типами значений.

PS Речь идет о Bad Hoor - старый друг :)

Бинарная тревога
источник
Я не хочу инициировать дату [поскольку вы используете его как выходной параметр] Хорошо, я перестану быть разборчивым!
Рубен Бартелинк
У меня нет компилятора, но поскольку DateTime является типом значения, компилируется ли метод расширения def?
Рубен Бартелинк,
Результат не вернется, если вы его не сделаете - [TestFixture] публичный класс WhenExnding {[Test] public void TryParseShouldWork () {DateTime? х = ноль; var res = Externders.TryParse (x, «01.01.1990»); Assert.IsTrue (res)
Рубен Бартелинк

; Assert.That (x! = Ноль); }} не работает в Assert.That, т.е. результат не изменяется, поскольку DateTime является типом значения (что всегда является хорошим вопросом для исключения на экранах телефонов: D)
Рубен Бартелинк
(obv первый (нерасширенный) будет работать, но он должен быть отключен, а не ref - и вы должны обнулить результат, если он не соответствует API TryXXX в целом - почти наверняка FDG упоминает об этом. Человек, я Я разборчивый!
Рубен Бартелинк
4

А как насчет создания метода расширения?

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
источник
2
Для чего нужен этот первый параметр dateTime? Никогда не используется.
Майк Зборай,
1
@mikez - вот как работают методы расширения, он используется компилятором, чтобы знать, что это должен быть метод расширения.
Эрик Фанкенбуш,
3
@MystereMan Я знаю, что такое метод расширения. Более подходящей сигнатурой для метода расширения будет DateTime? TryParse(this string dateString). Это просто причудливая реализация.
Майк Зборай,
3
@mikez - тогда почему ты спросил, для чего это было? Зачем загрязнять пространство имен строк, если оно нужно только для datetime? Цель состоит в том, чтобы предоставить аналог DateTime.TryParse, то есть DateTime? .TryParse
Эрик Фанкенбуш
1
@ErikFunkenbusch Этот метод расширения не допускает синтаксиса вызова, подобного (DateTime?).TryParse( ... )или Nullable<DateTime>.TryParse( ... ). Итак, Майк Зи прав, это глупая подпись метода.
Йеппе Стиг Нильсен,
1

Я не понимаю, почему Microsoft не справилась с этим. Небольшой умный служебный метод для решения этой проблемы (у меня была проблема с int, но замена int на DateTime будет иметь тот же эффект, может быть ...

    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
источник
1

Это тот лайнер, который вы ищете:

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

Если вы хотите сделать его правильным методом псевдорасширения TryParse, вы можете сделать это:

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
источник
@robnick Чем это отличается от того, что я сказал?
cpcolella
1
Не обращайте внимания на мой предыдущий комментарий (я поддержал ваше решение!), Для последней версии C # мне нужно было указать null: DateTime? d = DateTime.TryParse (мля, нет DateTime dt)? dt: (DateTime?) null;
Робник
1

Вот однострочное решение:

DateTime? d = DateTime.TryParse("text", out DateTime parseDate) ? parseDate : (DateTime?)null;
user1267054
источник
-3

В качестве альтернативы, если вас не беспокоит возможное возникшее исключение, вы можете изменить TryParse на Parse:

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

Хотя логического значения, указывающего на успех, тоже не будет, это может быть практично в некоторых ситуациях, когда вы знаете, что вводимый текст всегда будет действительным.

monsieurgutix
источник