将'int'与'null'进行比较会编译通过

9

可能是重复问题:
C#比较值类型与null是否可行

我刚才遇到了在C#(4.0)编译器中觉得奇怪的事情。

int x = 0;
if (x == null) // Only gives a warning - 'expression is always false'
    x = 1;

int y = (int)null; // Compile error
int z = (int)(int?)null; // Compiles, but runtime error 'Nullable object must have a value.'

如果你不能将null赋值给一个int,为什么编译器允许你比较它们(只会给出警告)?

有趣的是,编译器不允许以下操作:

struct myStruct
{
};

myStruct s = new myStruct();
if (s == null) // does NOT compile
    ;

为什么struct的例子不能编译通过,但是int的例子可以呢?

可能是因为你提到的警告非常明显。编译器可能会将其编译成 if (false)。这是正确的,x 永远不可能是 null - Simon Whitehead
此代码无法编译:int? z = (int)(int?)null; Error Nullable type must have a value。但是,这段代码可以编译通过:int? z = (int?)(int?)null; 试一下吧,祝你好运,编码愉快! - MethodMan
1
int z = (int)(int?)null; 可以编译通过。我理解 ? 的含义,但我的问题与 if (x == null) 有关。 - rhughes
我在这里看不出问题,如果(true == false),那也可以编译通过。这是因为运算符重载解析,有一个==运算符接受两个int?(可空类型)。由于int可以转换为int?,所以这将编译通过,但始终为false,基本上它选择了最佳的运算符重载,在这种情况下,由于右侧为空,它选择了int? == int? - sa_ddam213
编译可以通过,但会出错,因为你需要将(int)赋值为可空类型,这有意义。另外,“0”和“null”之间存在差异。 - MethodMan
显示剩余3条评论
2个回答

7

在进行比较时,编译器会尝试使比较的两个操作数具有兼容的类型(如果可能的话)。

这里有一个int值和一个常量null值(没有特定类型)。 在两个值之间唯一兼容的类型是int?,因此它们被强制转换为int?并作为int? == int?进行比较。 一些int值作为int?肯定是非空的,而null则肯定为空。 编译器意识到这一点,由于非空值不等于明确的null值,因此发出了警告。


编译器也会进行优化,因为它总是false。它甚至不会加载x变量。 - Simon Whitehead
在不支持Nullable<T>的.NET框架版本中,它是否可以编译? - Guillaume
@Guillaume:说实话,我不太确定,但我猜是的。在那种情况下,我想它们将被视为“对象”进行比较(并且将具有相同的警告)。 - Jeff Mercado
@Guillaume:根据Rich的更新,实际上看起来会失败。编译器似乎不会将值类型强制转换为“object”。 - Jeff Mercado
1
@Guillaume:Eric Lippert在重复的问题上的回答解释得更清晰。这只是因为有一个“==”运算符重载,它比较两个相同类型的可空类型。一般情况下,在值类型和引用类型之间不会有这样的重载,因此通常会失败。 - Jeff Mercado
@JeffMercado 所以我猜它在 .NET 1.1 中不会编译... - Guillaume

1
实际上,编译允许将“int?”与“int”进行比较,而不是将“int”与null进行比较,这是有道理的。
例如:
        int? nullableData = 5;
        int data = 10;
        data = (int)nullableData;// this make sense
        nullableData = data;// this make sense

        // you can assign null to int 
        nullableData = null;
        // same as above statment.
        nullableData = (int?)null;

        data = (int)(int?)null;
        // actually you are converting from 'int?' to 'int' 
        // which can be detected only at runtime if allowed or not

你试图在 int z = (int)(int?)null; 中实现的是:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接