.Net 2+:为啥 if( 1 == null ) 不再抛出编译器异常?
Posted
技术标签:
【中文标题】.Net 2+:为啥 if( 1 == null ) 不再抛出编译器异常?【英文标题】:.Net 2+: why does if( 1 == null ) no longer throw a compiler exception?.Net 2+:为什么 if( 1 == null ) 不再抛出编译器异常? 【发布时间】:2010-09-08 22:08:18 【问题描述】:我以int
为例,但这适用于.Net 中的任何值类型
在 .Net 1 中,以下会引发编译器异常:
int i = SomeFunctionThatReturnsInt();
if( i == null ) //compiler exception here
现在(在 .Net 2 或 3.5 中)该异常已经消失。
我知道这是为什么:
int? j = null; //nullable int
if( i == j ) //this shouldn't throw an exception
问题是因为int?
可以为空,而int
现在隐式转换为int?
。上面的语法是编译器的魔法。我们真的在做:
Nullable<int> j = null; //nullable int
//compiler is smart enough to do this
if( (Nullable<int>) i == j)
//and not this
if( i == (int) j)
所以现在,当我们执行i == null
时,我们得到:
if( (Nullable<int>) i == null )
鉴于 C# 正在执行编译器逻辑来计算这个,为什么它不能足够聪明地在处理像 null
这样的绝对值时不这样做?
【问题讨论】:
【参考方案1】:奇怪...用 VS2008 编译这个,目标是 .NET 3.5:
static int F()
return 42;
static void Main(string[] args)
int i = F();
if (i == null)
我收到编译器警告
warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'
它会生成以下 IL ... 据推测 JIT 会优化掉
L_0001: call int32 ConsoleApplication1.Program::F()
L_0006: stloc.0
L_0007: ldc.i4.0
L_0008: ldc.i4.0
L_0009: ceq
L_000b: stloc.1
L_000c: br.s L_000e
能发个代码sn-p吗?
【讨论】:
编译器正确地发现它永远不是真的,就像你做了 1==2 一样。知道 int 可以隐式转换为 int 就足够聪明了?那int?可以与null进行比较。我怀疑优化器足够聪明,可以去掉整个块。【参考方案2】:2.0 框架引入了可空值类型。即使字面常量“1”永远不能为 null,它的基础类型 (int) 现在可以转换为 Nullable int 类型。我的猜测是编译器不能再假设 int 类型不可为空,即使它是一个字面常量。编译 2.0 时确实收到警告:
警告 1 表达式的结果始终为“假”,因为“int”类型的值永远不会等于“int?”类型的“null”?
【讨论】:
就像我说的 - 编译器知道 int 可以隐式转换为 int?和int?可以与null进行比较。对于任何永远不真实的比较,该警告都是一般性的。 1==2 会抛出同样的警告。【参考方案3】:这应该是编译时错误,因为类型不兼容(值类型永远不能为空)。可惜没有。
【讨论】:
阅读整个问题,我会解释它发生的原因。问题是为什么不能将其视为特例。 当我说“应该”时,我的意思是存在道德上的要求,而不是我期望编译器做的事情。你描述的理由一点也不令人信服。他们应该使这成为静态编译失败。【参考方案4】:警告是新的(我认为是 3.5) - 错误与我执行 1 == 2
时的错误相同,它很聪明,可以发现它永远不会正确。
我怀疑通过完整的 3.5 优化,整个语句将被删除,因为它非常聪明,从来没有真正的评估。
虽然我可能希望 1==2
编译(例如,在我测试其他东西时关闭功能块)但我不希望 1==null
编译。
【讨论】:
【参考方案5】:我不认为这是编译器问题本身;整数值永远不会为空,但将它们等同的想法并非无效;这是一个始终返回 false 的有效函数。编译器知道;代码
bool oneIsNull = 1 == null;
编译,但给出编译器警告:The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type '<null>'
。
因此,如果您希望恢复编译器错误,请转到项目属性并为此错误打开“将警告视为错误”,您将再次开始将它们视为破坏构建的问题。
【讨论】:
【参考方案6】:当您将不可为空的类型与 null 进行比较时,编译器仍然会生成警告,这正是它应该的方式。可能是您的警告级别太低,或者这在最近的版本中已更改(我只在 .net 3.5 中这样做)。
【讨论】:
以上是关于.Net 2+:为啥 if( 1 == null ) 不再抛出编译器异常?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 null 是一个对象,null 和 undefined 有啥区别?
为啥 ASP.Net MVC 模型绑定器将空 JSON 数组绑定到 null?
DateTime.hasvalue vs datetime == null,哪个更好以及为啥[重复]
为啥复选框选择列表总是在 ASP.NET MVC-5 中发布为 null [重复]
关于html5 canvas元素 为啥在chrome和火狐里都显示不了。去掉 if (canvas == null) return false;才行