为什么允许“long value”等于null?
当我调试几行代码并问我原因为什么它无法正常工作时我偶然发现了这种情况……
if(answer.AnswerID == null) { // do something }
实际上它应该是这样的:
if(answer == null) { // do something }
-
answer
是answer
类型的对象Answer - a class
。 -
AnswerID
是long
类型的属性。
奇怪的是,如果你尝试这样的事情:
long myLongValue = null;
编译器会显示错误:
Connot convert null to long ...
所以我的问题是:当我尝试将long type
与null
进行比较时,为什么我没有得到编译错误 ?
EDITED
这个问题不是关于nullable
类型的。
我问为什么.NET允许我将长变量与null进行比较。 我说的是long type
而不是long ? type
long ? type
。
正如@Tim指出的那样,您不会因以下代码而出错:
long foo = 42; if (foo == null) { }
你会得到一个警告:
表达式的结果始终为“false”,因为“long”类型的值永远不会等于“long”类型的“null”。
这会产生警告而不是错误,因为提升的运算符在C#语言规范中定义如下:
提升的运算符允许在非可空值类型上运行的预定义和用户定义的运算符也可以与这些类型的可空forms一起使用。 […]对于平等运营商
== !=
如果操作数类型都是非可空值类型并且结果类型是bool,则存在提升forms的运算符。 提升forms是通过添加一个? 每个操作数类型的修饰符。 提升的运算符认为两个空值相等,并且空值不等于任何非空值。 如果两个操作数都为非null,则提升的运算符将解包操作数并应用基础运算符以生成bool结果。
在这种情况下,“底层运算符”是预定义值类型long
‘s ==
运算符 :
对于预定义的值类型,如果操作数的值相等,则相等运算符(==)返回true,否则返回false。
因为foo
是隐式转换的( “对非可空值类型进行操作的预定义隐式转换也可以与这些类型的可空forms一起使用。”)并且null
文本也被隐式转换( “隐式转换从空文本存在到任何可以为空的类型。“ ),表达式:
(long)foo == null
变为:
(long?)foo == (long?)null
其中,假设foo
的类型为long
,因此总是有值,则始终返回false,甚至不应用long
的==
运算符。
我不完全确定,但我怀疑这是存在的,以便在没有显式转换的情况下在可空和非可空值之间进行比较:
long? foo = 42; long bar = 42; Console.WriteLine(foo == bar); // true foo = null; Console.WriteLine(bar == foo); // false
如果这不是由上面指定的语言处理的,你会得到“运算符==
不能应用于long?
类型和long
类型的操作数” ,因为Nullable
没有==
运算符,并且没有==
运算符接受long?
。
它会编译,甚至会执行,因为编译器会评估==
并提升long
到long?
因为这是与存在的==
实现最接近的匹配。
这确实不是最好的行为,它有点像VB 🙂
long
盒装,条件总是false
。
long l = 0; Console.WriteLine(l == null); //false
这应该给你一个警告:
表达式的结果始终为“false”,因为“long”类型的值永远不会等于“long”类型的“null”。
Resharper也对此发出警告。 这总是一个错误,也许是重构失败的遗留物。
有关可空类型的信息,请查看此处 。 像long和int这样的普通值类型通常不能为null。
当你试图将它与null比较时它没有失败的原因是因为它进行了比较并且它不是null。 所以没有错误。