如何在可空<DateTime>中使用DateTime.TryParse?

138

我想使用DateTime.TryParse方法将字符串转换为可空的日期时间值。但是当我尝试这样做时:

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

编译器告诉我:

“out”参数未被归类为变量。

不确定我需要在这里做什么。 我也尝试过:

out (DateTime)d.Value 

还有一个问题,那个方法也不起作用。你有什么想法吗?

9个回答

186

正如Jason所说,您可以创建一个正确类型的变量并传递它。您可能希望将其封装在自己的方法中:

就像Jason所说,你可以创建一个合适类型的变量并传参。您可能需要将其封装在自己的方法中:

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;

7
我可能不应该与The Skeet争论,但是……你应该将你的方法命名为Parse,因为我会期望名为TryParse的方法遵循TryParse惯例并返回一个布尔值。;-) - Myster
1
@Myster:在这两种情况下,它都没有遵循现有的约定-那些只使用“Parse”的人会期望它返回“DateTime”并在失败时抛出异常,对吧?但是是的,你可以做任何你想做的事情...在Noda Time中,我已经将相关方法命名为“Parse”。 - Jon Skeet
1
在您的第一个例子中,“else”关键字是不必要的,因为“if”块的终点永远无法到达。 - Jeppe Stig Nielsen
2
@JeppeStigNielsen:是的,这并不必要 - 但对于对称性而言可能在风格上更可取。这只是个人偏好(而且我也不一致……) - Jon Skeet
通过使用 return null; 避免 Arrowhead anti-pattern else { return null; }。查看链接:https://blog.codinghorror.com/flattening-arrow-code/ - Kiquenet
4
使用else可以更清楚地表示会选择其中一条路径并返回结果。我反对使用大量嵌套的代码,但在这种情况下,我认为这并不是一个问题。 - Jon Skeet

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

(可能还有更优雅的解决方案,但为什么不像上面那样简单地做呢?)


4
没错,我一开始是想要一个简单的一行代码来解决问题,但这个方法也可以。不太喜欢创建临时变量,感觉有点混乱。这种情况似乎应该得到更好的支持。 - Brian Sullivan
1
看看 Binary Worrier 的建议,将其伪内联到扩展方法中。 - David Alpert
4
为什么要将 DateTime 强制转换为 DateTime?在传递 d2 到 TryParse 方法之前,不需要重新转换数据类型。 - Aaron Powell
@Slace -- 我更新了答案以包含你的建议。 - Drew Noakes
@Jason Kealey 我希望这已经在VS2012中引入了,否则我将不得不继续使用这个好的代码片段。 - Pimenta

24

这是Jason建议的略微简化版:

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

希望这可以帮助你 :)

编辑: 移除了(显然)未经充分测试的扩展方法,因为(正如一些不好的人指出的那样),试图改变“this”参数的扩展方法将无法与值类型一起使用。

P.S. 相关的坏人是我老朋友 :)


你不想初始化日期[因为你将其用作输出参数]好的,我不再挑剔了! - Ruben Bartelink
我手头没有编译器,但是由于DateTime是值类型,这个扩展方法是否能够编译通过呢? - Ruben Bartelink
;Assert.That( x != null ); } }在Assert.That上失败了,即结果没有被修改,因为DateTime是一个值类型(这通常是电话面试中的一个好问题:D) - Ruben Bartelink
(显然第一个(非扩展名)将起作用,但应该是out而不是ref - 如果无法适应TryXXX API,则应将结果置为空 - 我相当挑剔!) - Ruben Bartelink
显然,所展示的样例仅供说明目的...(Ruben,别再挑刺了,你这个坏蛋!) - Binary Worrier
显示剩余3条评论

7

这就是您正在寻找的一行代码:

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

@robnick,这与我所说的有何不同? - cpcolella
2
忽略我的先前评论(我已经赞同了你的解决方案!),对于最新的C#,我需要将null强制转换为:DateTime?d = DateTime.TryParse(blah,out DateTime dt)?dt:(DateTime?)null; - robnick
遇到了相同的问题;我认为在这个一行代码中,null必须被转换为DateTime?,是吗? - James Skemp
注意:这个答案(以及几乎所有其他答案)如果失败,将覆盖d中的任何现有值为null,这可能是一个意外的副作用(在我的情况下,因为解析FHIR中的一堆可能的日期字段)。使用Cpcolella上面的一行代码,但以“if”语句的形式,可以防止这种情况。if (DateTime.TryParse("some date text", out DateTime dt) { d = dt } - mochsner

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;

    }
}

2
第一个参数 dateTime 是用来干什么的?它从未被使用过。 - Mike Zboray
1
@mikez - 这就是扩展方法的工作原理,编译器使用它来知道它应该是一个扩展方法。 - Erik Funkenbusch
3
我知道什么是扩展方法。一个更合适的扩展方法签名应该是 DateTime? TryParse(this string dateString)。这个实现方式太奇怪了。 - Mike Zboray
3
@mikez - 那你为什么要问它是用来做什么的?既然你只需要它来处理日期时间,为何要污染字符串名称空间?它的目的是提供一个类似于DateTime.TryParse的模拟方法,即DateTime?.TryParse。 - Erik Funkenbusch
1
@ErikFunkenbusch 这个扩展方法将___不会___允许像(DateTime?).TryParse( ... )或者Nullable<DateTime>.TryParse( ... )这样的调用语法。所以Mike Z是对的,这个方法的签名很愚蠢。 - Jeppe Stig Nielsen
显示剩余3条评论

1
这是一行简洁的解决方案:
DateTime? d = DateTime.TryParse("text", out DateTime parseDate) ? parseDate : (DateTime?)null;

5
所以......你只是在四个月后复制了我的答案? - cpcolella

1

我不明白为什么微软没有处理这个问题。一个聪明的小工具方法来处理这个问题(我遇到了int类型的问题,但用DateTime替换int将产生相同的效果,可能会更好.....

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

-3

或者,如果你不关心可能引发的异常,你可以将TryParse更改为Parse:

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

虽然也不会有一个布尔值指示成功,但在某些情况下,这可能是实用的,特别是当您知道输入文本始终有效时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接