使用 ?: 条件运算符时的可空类型问题

160

能有人解释一下为什么这个在C#.NET 2.0中有效吗:

    Nullable<DateTime> foo;
    if (true)
        foo = null;
    else
        foo = new DateTime(0);

...但这不会:

    Nullable<DateTime> foo;
    foo = true ? null : new DateTime(0);

后一种形式导致我出现编译错误:“条件表达式的类型无法确定,因为<null>和'System.DateTime'之间不存在隐式转换。”

并不是说我不能使用前一种形式,但第二种风格与我的其余代码更加一致。


12
使用DateTime?可以节省大量的输入,而不是使用Nullable<DateTime>。 - Stewart Johnson
5个回答

338

编译器告诉你它不知道如何将null转换为DateTime

解决方法很简单:

DateTime? foo;
foo = true ? (DateTime?)null : new DateTime(0);
请注意,Nullable<DateTime>可以写成DateTime?,这将节省您大量的打字时间。

工作得足够好,但现在您无法对foo进行空值检查 - 它将始终具有值。没有任何绕过此问题的方法 - 正如MojoFilter所说:“这是因为在三元运算符中,两个值必须是相同的类型。” - DilbertDave
@DilbertDave,MojoFilter的帖子中的信息是不正确的。 - Mishax
4
我想补充一点,编译器尝试通过查看操作数来猜测三元操作的结果类型,而不是通过查看分配给其的变量。它发现 <null>DateTime,而不是找到共同的祖先类型,只是试图在它们之间找到转换。(额外信息:C# 识别 <null> 类型,即每个 null 表达式的类型。) - IS4
如果已经有很多人问过了,那么重复问题标记在哪里? - starmandeluxe
@starmandeluxe,他们都可能指向这里(至少我是这样来到这里的) - Scott Chamberlain

20

顺便提一下(离题了,但与可为空类型有关),我们有一个方便的运算符专门用于可为空类型,它被称为null合并运算符。

??

这样使用:

// Left hand is the nullable type, righthand is default if the type is null.
Nullable<DateTime> foo;
DateTime value = foo ?? new DateTime(0);

9
这怎么回答他的问题了? - Stewart Johnson
3
如果满足某个条件,Nick希望将空值赋给foo。如果foo为空,则使用Null合并运算符将DateTime(0)赋值给value。这两者完全没有关联。 - Jeromy Irvine
4
顺便提一下,虽然不是主题,但这是一个有趣的事情值得知道。 - FlySwat
啊,好的。知道这个还是挺有用的。 - Jeromy Irvine

8

这是因为在三元运算符中,两个值必须解析为相同的类型。


10
不需要,它们不必是相同类型。第二个操作数必须可以隐式转换为第三个操作数的类型,或者反过来。 - Mishax

3

我知道这个问题是在2008年提出的,现在已经过去了5年,但被标记为答案的答案并没有让我满意。真正的答案是DateTime是一个结构体,作为结构体它与null不兼容。你有两种解决方法:

第一种是使null与DateTime兼容(例如,像获得70个赞的先生建议的那样将null强制转换为DateTime?,或者将null强制转换为Object或ValueType)。

第二种方法是使DateTime与null兼容(例如,将DateTime强制转换为DateTime?)。


3
另一个类似于已接受的解决方案是使用 C# 的 default 关键字。虽然定义时使用了泛型,但实际上适用于任何类型。
应用于 OP 问题的示例用法:
Nullable<DateTime> foo;
foo = true ? default(DateTime) : new DateTime(0);

使用当前已接受的答案的示例:

DateTime? foo;
foo = true ? default(DateTime) : new DateTime(0);

另外,通过使用default,您无需将变量指定为nullable以赋予其null值。编译器将自动分配特定变量类型的默认值,并且不会遇到错误。例如:

DateTime foo;
foo = true ? default(DateTime) : new DateTime(0);

14
不正确,default(DateTime) 不是 null,它是 "1.1.0001 0:00:00",与 new DateTime(0) 相同。 - IS4
@IllidanS4,我并没有说它等于 null,只是通过使用 default(),你可以将其赋值给一个 nullable 的值(正如MSDN所述)。我展示的例子演示了它可以与 Nullable<DateTime>DateTime? 和简单的 DateTime 一起使用的多功能性。如果你认为这是不正确的,能否提供一个 PoC 来证明这些失败? - newfurniturey
4
问者希望将null存储在变量中,而不是default(DateTime),所以这最多是误导性的。正如您所暗示的那样,这并不是“万能”的,因为整个表达式仍然具有相同的类型 - DateTime,您可以用new DateTime()替换default(DateTime)来实现相同的效果。也许您想说的是default(DateTime?),因为它实际上等于null - IS4

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