C# if语句简写操作符(? :)导致代码无法访问

13

为什么我在使用Visual Studio 2010的C#时会收到这个警告?

"Unreachable expression code detected"

从以下代码中(绿色波浪线下划线的DateTime.Now):

public DateTime StartDate
{
  get
  {
    DateTime dt = (DateTime)ViewState["StartDate"];
    return ((dt == null) ? DateTime.Now : dt);
  }
}

4
好的,因为DateTime是一个结构体,永远不可能为null。那么我在ViewState中检查什么值是空的? - JohnB
“不可到达的表达式”听起来与“始终评估为(TRUE|FALSE)”非常接近……你确定‘dt’可能是‘null’吗?或者经典的“if {} else {}”也能正常工作吗? - Nick T
错别字:那么如果我的“ViewState”为空,我应该检查什么值? - JohnB
1
多么令人惊叹的编译器!感谢编译器 :) - JohnB
6个回答

38

因为 DateTime 结构体永远不会为 null。

如果您期望有可能为空的值,则必须使用可空的 DateTime 结构体。您也可以使用 null 合并运算符而不是条件运算符:

public DateTime StartDate
{
    get
    {
        DateTime? dt = (DateTime?)ViewState["StartDate"];
        return dt ?? DateTime.Now;
    }
}

或者你可以将其写成一行代码(就像评论中的那样):

public DateTime StartDate
{
    get { return (DateTime)(ViewState["StartDate"] ?? DateTime.Now); }
}

1
如果"StartDate"键不存在会发生什么? - Blam
5
在ASP.NET中,如果ViewState关键字不存在,你会得到null。我通常使用一行代码来表达与@Justin相同的意思:return (DateTime)(ViewState["StartDate"] ?? DateTime.Now);。 这很有效。 - kbrimington
@Blam:我正准备问这个问题呢!@Justin:好的解决方案,谢谢! - JohnB
@Blam:如果StartDate不存在,dt将为null,然后合并运算符(??)将返回右侧(DateTime.Now)。 - Ricardo Villamil
我原本以为 return dt ?? DateTime.Now; 无法编译通过,因为 dtNullable<DateTime> 类型而返回类型是 DateTime。然而,它被编译成了等价于 return dt.HasValue ? dt.GetValueOrDefault() : DateTime.Now;。有趣的发现。 - Anthony Pegram
3
@Anthony: 确定空值合并运算符的结果类型的规则相当复杂,但通常会得出合理的结果。毕竟,运算符的意图是消除空值,因此我们希望尽可能地转换为非可空类型。有关详细信息,请参阅语言规范。 - Eric Lippert

4

DateTime 是一个值类型,因此它永远不会为空。因此,在编译时,对 == null 的测试将评估为常量 false,因此 ?: 的一半将永远不会在运行时到达。


4
已经给出的答案——非空值类型永远不会为null,因此比较在编译时已知返回false——是正确的,您可能会想到一个显而易见的后续问题:为什么这甚至是合法的?这个问题在SO上已经被问了很多次;简短的版本是,C#为每个提供非空值类型等于运算符的结构提供了“升级”的等于运算符(如果升级运算符不存在的话)。
也就是说,因为DateTime提供了一个==运算符,编译器自动地生成了一个DateTime?的==运算符,并且那个运算符适用于您的情况。

另一个经常被问到的问题是,为什么编译器会忘记发出其他警告:“表达式的结果始终为“false”,因为类型为“System.DateTime”的值永远不等于类型为“System.DateTime?”的“null””。这个警告可以在内置的提升相等运算符==中工作(至少大多数情况下),比如42 == null,但对于用户定义的运算符==,比如在DateTime上的运算符,在它们被提升时将不起作用。 - Jeppe Stig Nielsen
1
@JeppeStigNielsen:缺失的警告是一个错误;我怀疑是我在C#3中引入了它。当我在微软时,我从来没有把它作为一个高优先级的事情来全面调查;我不知道它是否在Roslyn中修复了。对于这个错误我感到非常遗憾。 - Eric Lippert

3

可能是因为DateTime是一个结构体(值类型),而不是引用类型。
因此,将其与null进行比较将始终为false。


1

日期时间不能为空


1

DateTime不可为空,因此其值永远不会为null。


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