.Net 2+:为什么if(1 == null)不再抛出编译器异常?
我以" 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 )
考虑到Cis正在执行编译器逻辑来计算此值,为什么在处理诸如`null'之类的绝对值时,为什么它不足够聪明而不执行该操作呢?
解决方案
回答
当我们将不可为null的类型与null进行比较时,编译器仍会生成警告,这只是应有的方式。可能是警告级别过低或者在最新版本中已更改(我仅在.net 3.5中进行了更改)。
回答
奇怪...以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
我们可以发布代码段吗?
回答
我不认为这本身就是编译器问题;整数永远不会为空,但是将它们相等的想法并不是无效的。这是一个始终返回false的有效函数。而且编译器知道;代码
bool oneIsNull = 1 == null;
可以编译,但会警告编译器:`表达式的结果始终为'false',因为类型'int'的值永远不等于类型'<null>'的'null'。
因此,如果我们希望返回编译器错误,请转至项目属性,然后为该错误打开"将警告作为错误处理",然后我们将开始再次将它们视为构建中断问题。
回答
警告是新的(我认为是3.5),错误与我执行过'1 == 2'一样,它很聪明,可以发现从未有过的错误。
我怀疑通过3.5的优化,整个语句将被删除,因为它很聪明,而且从来没有真正的评估。
虽然我可能希望1 == 2
进行编译(例如在测试其他内容时关闭功能块),但我不想1 == null
来编译。
回答
这应该是编译时错误,因为类型不兼容(值类型永远不能为null)。很遗憾,事实并非如此。
回答
2.0框架引入了可为空的值类型。即使文字常量" 1"永远不能为null,现在也可以将其基础类型(int)强制转换为Nullable int类型。我的猜测是,即使编译器是文字常量,编译器也不能再假定它不能为空。编译2.0时,我确实收到警告:
警告1由于类型'int'的值永远不会等于'int?'类型的'null',因此表达式的结果始终为'false'。