将struct与null进行比较时,编译器警告错误

请考虑以下代码:

DateTime t = DateTime.Today; bool isGreater = t > null; 

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

警告CS0458:表达式的结果始终为’bool’类型的’null’

这是不正确的; 结果始终为false (类型为bool ):

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

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

这也产生了同样的错误警告。 这里>运算符是提升运算符。 如果其两个操作数中的任何一个的HasValue为false,则返回false 。 否则,提升的运算符将继续将两个操作数展开到底层结构,然后调用该结构定义的>的重载(但在这种情况下,如果一个操作数不是HasValue则不需要)。

你能重现这个bug吗?这个bug是众所周知的吗? 我误解了什么吗?

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

(现在如果我们使用==而不是> ,一切都应该完全相似(因为DateTime也会重载==运算符)。但它不相似。如果我说

 DateTime t = DateTime.Today; bool isEqual = t == null; 

没有得到警告☹有时你会看到人们不小心检查变量或参数为null,没有意识到他们的变量类型是一个结构(它重载==而不是像int这样的简单类型)。 如果他们得到警告会更好。)


更新:使用Visual Studio 2015的C#6.0编译器(基于Roslyn ),上面isGreater的错误消息isGreater改为带有正确且有用的警告消息的CS0464。 此外,在VS2015的编译器中修复了缺少上述isEqual的警告,但只有在使用/features:strict编译时才能修复。

你是对的: 这是Visual Studio中的一个错误 。 C#4.0标准(§7.3.7解除运营商)有这样的说法:

对于关系运算符

 < > <= >= 

[…] 如果一个或两个操作数为空,则提升的运算符将生成值false

事实上,在MonoDevelop中,您会收到以下警告:

System.DateTime类型与null进行比较的结果始终为false

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

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

顺便提一下,我将在本月晚些时候(2012年12月)讨论Roslyn如何在http://ericlippert.com上优化提升表达式,所以如果这个主题让你感兴趣,请查看:

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

 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,因此警告。