2012-10-24 36 views
11

考虑下面的代码:错误编译器警告时,比较结构为空

DateTime t = DateTime.Today; 

bool isGreater = t > null; 

使用Visual Studio 2010(C#4,.NET 4.0),我得到以下警告:

警告CS0458 :表达式的结果总是'null',类型为'bool?'

这是不正确的;结果总是false(的bool型):

现在,该结构的DateTime重载>(大于)运算符。任何不可为空的结构(如DateTime)都可以隐式转换为相应的Nullable<>类型。以上表达式完全等同于

bool isGreater = (DateTime?)t > (DateTime?)null; 

它也会产生相同的错误警告。这里的>运营商是运营商解除。如果HasValue的两个操作数中的任何一个是false,则返回false。否则,解除操作符将继续将两个操作数解包到底层结构中,然后调用由该结构定义的过载>(但在这种情况下,其中一个操作数不是HasValue)。

你能重现这个bug吗,这个bug是否是众所周知的?我误解了一些东西吗?

这对所有结构类型(不是简单的类型,如int,而不是枚举类型)都是相同的,这会重载相关运算符。

(现在,如果我们使用==代替>,一切都应该是完全相似(因为日期时间也重载==运营商),但它不是相似的。如果我说

DateTime t = DateTime.Today; 

bool isEqual = t == null; 

我得到没有警告☹有时你会发现人们不小心检查了一个变量或参数为null,没有意识到它们的变量类型是一个结构体(它超载==,而不是简单的类型,如int)。如果他们得到警告)


更新:与Visual Studio 2015的C#6.0编译(基于Roslyn)中,用isGreater不正确的消息上方改变为CS0464具有正确的和有益的警告消息。此外,以上isEqual缺少警告在VS2015的编译器中是固定的,但只有在编译时使用/features:strict

+0

'[任何]> null“没有任何意义(至少对我来说)。尽管如此,有趣的问题是,我认为它应该警告'bool'总是以'false'结尾。 – Alex

+1

可能会有所帮助:http://blogs.msdn.com/b/abhinaba/archive/2005/12/11/501544.aspx和http://blogs.msdn.com/b/abhinaba/archive/2005/12 /14/503533.aspx – Habib

+0

有趣的是,'DateTime.CompareTo(object)'_specifically_返回'1'当与'null'比较时,无论传入的对象类型如何。 – Rawling

回答

5

你是对的:这是Visual Studio中的一个错误。的C#4.0标准(§7.3.7抬升操作者)已这样说的:

对于关系运算符

< > <= >= 

[...] 的提升运算,如果一个或两个操作数产生的值false为空。 ...

而事实上,在MonoDevelop中,你会得到如下的警告,而不是:

null比较型System.DateTime的结果总是false

+0

但是,在这个' >'case,结果是false,不是null。结果的类型是'bool',而不是'bool?'。 – Rawling

+0

@Rawling是吗?这听起来是错误的,因为操作员被解除了,它肯定应该是'bool?'。 –

+0

Visual Studio似乎是这么认为的,但是'DateTime.Today> null'给了''bool'类型的'false',并且提问者显然得到了同样的结果。我同意这很奇怪。 – Rawling

1
DateTime t = DateTime.Today; 

bool isGreater = (DateTime?)t > (DateTime?)null; 

在这种情况下警告的是t > null。这永远不会是真的。因为它不能被评估。

在这种情况下:

bool isGreater = (DateTime?)t > (DateTime?)null; 

我们正在评估(DateTime?)t > (DateTime?)null;

或基本上在最好的情况下t > null;和之前一样。 DateTime.Now永远不会大于Undefined,因此是警告。

+0

我同意它与警告有关,但你有没有阅读警告**消息**?这是警告的文本​​是令人不安的错误,而不是发出警告的事实。 (也许在开发可空类型的某些时候,他们计划让提升的比较运算符('>','=='等)有不同的表现,但后来改变了主意?) –

9

我在Roslyn中实现提升的操作员行为时独立发现了这个错误,并且在我离开之前我在Roslyn中修复了它。

对不起,我在10月份发布时没有看到。感谢您将它提交给Connect!对于错误的许多道歉;这在操作语义分析中是一个长期存在的错误。

顺便说一句,我将讨论如何罗斯林可优化http://ericlippert.com本月(2012年12月)后解除表达,因此,如果这个问题你感兴趣,检查出来:

http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/

+3

没有必要为没有看到堆栈溢出的每个线程而道歉。我希望我记得在提升的运营商上检查即将发布的帖子。 –