.Net 2+:为什么 if( 1 == null ) 不再抛出编译器异常?
-
09-06-2019 - |
题
我在用着 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
?
解决方案
我不认为这是编译器问题 本身;整数值永远不会为空,但使它们相等的想法并不是无效的;这是一个总是返回 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>'
.
因此,如果您希望返回编译器错误,请转到项目属性并针对此错误打开“将警告视为错误”,然后您将再次开始将它们视为破坏构建的问题。
其他提示
奇怪的 ...使用 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
您可以发布代码片段吗?
当您将不可空类型与 null 进行比较时,编译器仍然会生成警告,这正是它应该的方式。可能是您的警告级别太低,或者在最近的版本中已更改(我只在 .net 3.5 中这样做)。
2.0 框架引入了可为空值类型。尽管文字常量“1”永远不能为 null,但其基础类型 (int) 现在可以转换为 Nullable int 类型。我的猜测是,编译器不能再假设 int 类型不可为空,即使它是文字常量。编译 2.0 时我确实收到警告:
警告 1 表达式的结果始终为“false”,因为“int”类型的值永远不等于“int?”类型的“null”?
警告是新的(我认为是 3.5) - 错误与我所做的相同 1 == 2
, ,它足够聪明,可以发现这根本不是真的。
我怀疑,通过全面的 3.5 优化,整个声明将被删除,因为它非常聪明,从来没有真正的评估。
虽然我可能想要 1==2
编译(例如,在测试其他东西时关闭功能块)我不想要 1==null
到。
它应该是一个编译时错误,因为类型不兼容(值类型永远不能为空)。令人遗憾的是事实并非如此。