11

考虑以下代码:

DateTime t = DateTime.Today;

bool isGreater = t > null;

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

警告 CS0458:表达式的结果始终为“布尔”类型的“空”?

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

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

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

这也会产生相同的错误警告。这里的>算子是被提升的算子。HasValue如果它的两个操作数中的任何一个是 ,则此方法通过返回 false 来工作false。否则,提升的运算符将继续将两个操作数解包到底层结构,然后调用>由该结构定义的重载(但在一个操作数没有的情况下,这不是必需的HasValue)。

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

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

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

DateTime t = DateTime.Today;

bool isEqual = t == null;

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


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

4

3 回答 3

9

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

很抱歉,当您在 10 月份发布它时,我没有看到这个。感谢您将其提交给 Connect!并为错误道歉;这是算子语义分析中长期存在的错误。

Incidentally, I'll be discussing how Roslyn optimizes lifted expressions on http://ericlippert.com later this month (December 2012), so if this subject interests you, check it out:

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

于 2012-12-19T00:26:02.780 回答
5

你是对的:这是 Visual Studio 中的一个错误。C# 4.0 标准(§ 7.3.7 提升运算符)有这样的说法:

对于关系运算符

<  >  <=  >=

[…]如果一个或两个操作数为空,则提升的运算符会产生值。false…</p>

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

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

于 2012-10-24T09:39:52.840 回答
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,因此会发出警告。

于 2012-10-24T09:19:21.810 回答