2011-10-30 35 views
2

我有一个名为EmailMessage的对象,它具有一个名为Timestamp的可以为空的System.DateTime字段。在我的C#代码中,我有以下行:C#条件运算符的返回类型

var TS = EmailMessage.Timestamp == null ? System.DateTime.Now : EmailMessage.Timestamp; 

为什么.NET 4推断TS的数据类型为System.DateTime?而不是System.DateTime(换句话说,为什么.NET 4认为TS是可空的?)对我来说TS似乎是非常明显的,TS绝对不是空的。

在此先感谢您的帮助。

回答

5

因为C#编译器只是着眼于各类DateTime.NowEmailMessage.Timestamp :-)

而且我要告诉你一件事:我能打破你的假设。假设有两个线程。一个线程有你的代码,另一个线程有EmailMessage.Timestamp = null。另一个线程在EmailMessage.Timestamp == nullTS = EmailMessage.Timestamp之间执行。破:-)

我要补充的是你的代码通常是这样写的:

var TS = EmailMessage.Timestamp ?? System.DateTime.Now; 

使用?? Operator这样编译器知道TS不能为空。

+0

非常明确的解释。感谢您提供有关空合并运算符的指针。 – Shredderroy

2

如果EmailMessage.Timestamp为Nullable<T>,那么这是唯一有效的选项。在真实情况下,它变成一个总是有价值的Nullable<DateTime>;在假的情况下,它假定时间戳的值,该值可能有或没有值。

它不做任何进一步的分析。但是,您可以使用不可空的EmailMessage.Timestamp.Value

在一般情况下,属性可以在不同的调用之间改变值,所以检查null并不安全,并且假设它下一次为null。这不会发生在这里,但这就是为什么C#编译器不做任何假设。

这里简单的形成大概是:

var ts = EmailMessage.Timestamp ?? DateTime.Now; 
+0

如果你有多个线程,它也可能发生在这里。 –

+0

“在假的情况下,它假定时间戳的值,该值可能有或没有值” - nah。 '时间戳'始终有一个值。我认为你的第一段可能是错误的。 –

+0

@Albin它取决于EmailMessage是什么 - 变量,字段,属性等 - 但是;你是对的 –

2

,因为有一个隐式转换从DateTimeDateTime?(而不是走另一条路,你不喜欢的东西condition ? EmailMessage.TimeStamp : null

但你。应该在这里使用null-coalescing运算符:

var TS = EmailMessage.TimeStamp ?? DateTime.Now 
+0

感谢您提及空合并运算符。 – Shredderroy

1

你可能会在之后如此mething喜欢这个代替:

var TS = EmailMessage.TimeStamp == null ? DateTime.Now : EmailMessage.TimeStamp.Value; 

或许

var TS = (EmailMessage.TimeStamp ?? DateTime.Now).Value; 
1

EmailMessage.Timestamp总是DateTime?。如果您检查之前是否为空,则无关紧要。编译器不关心,不应该在意。在多线程应用程序EmailMessage.Timestamp中可以在检查和您使用该值的位置之间切换。形成一个编译器透视图EmailMessage.Timestamp可以在以后使用它时为空,并且应该具有DateTime?类型。