【问题标题】:Wrong compiler warning when comparing struct to null将 struct 与 null 进行比较时出现错误的编译器警告
【发布时间】:2012-10-14 07:26:34
【问题描述】:

考虑以下代码:

DateTime t = DateTime.Today;

bool isGreater = t > null;

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

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

这是不正确的;结果总是 falsebool 类型):

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

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

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

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

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

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

DateTime t = DateTime.Today;

bool isEqual = t == null;

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


更新: 使用 Visual Studio 2015 的 C# 6.0 编译器(基于 Roslyn),上面带有 isGreater 的错误消息更改为带有正确且有用的警告信息。此外,上面isEqual 缺少警告已在VS2015 的编译器中修复,但前提是您使用/features:strict 进行编译。

【问题讨论】:

标签: c# comparison nullable compiler-warnings lifted-operators


【解决方案1】:

我在 Roslyn 中实现提升运算符行为时独立发现了此错误,并在离开之前在 Roslyn 中修复了它。

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

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

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

【讨论】:

  • 没有必要为没有看到 Stack Overflow 上的每个线程而道歉。我希望我记得查看您即将发布的关于提升运算符的帖子。
【解决方案2】:

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

对于关系运算符

<  >  <=  >=

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

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

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

【讨论】:

  • 但是,在这个&gt; 的情况下,结果是假的,而不是空的。结果的类型是bool,而不是bool?
  • @Rawling 是吗?听起来不对,应该是bool?,因为运营商被解除了。
  • Visual Studio 似乎是这么认为的,但DateTime.Today &gt; null 给了我false 类型的bool,而提问者显然也一样。我同意这很奇怪。
  • 您:这通常适用于所有运算符,而不仅仅是加法。 不,请阅读 C# 语言规范的“提升运算符”部分。提升的运算符==&gt; 返回bool,就像原来的运算符一样。这与 + 运算符不同。提升的+ 运算符(一元和二元)返回DateTime?(可为空),因为未提升的形式返回DateTime(不可为空)。
  • 由于这个答案更好,我将其标记为已接受。编辑后这是一个很好的答案。如果这是一个已知的错误,没有人提供参考,所以我提交了它。见this feeback item at Connect
【解决方案3】:
DateTime t = DateTime.Today;

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

在这种情况下,警告是关于t &gt; null。那永远不会是真的。因为无法评价。

在这种情况下:

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

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

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

【讨论】:

  • 我同意它与警告有关,但您是否阅读过警告消息?令人不安的是警告的文本​​,而不是发出警告的事实。 (也许在开发可空类型的某个时候,他们计划让提升的比较运算符(&gt;== 等)表现不同,但后来改变了主意?)
猜你喜欢
  • 2018-09-11
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多