为什么允许"long value"等于null?

Fel*_*sso 28 .net c#

当我调试几行代码并问我原因为什么它不起作用我偶然发现了这种情况...

if(answer.AnswerID == null) 
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)

实际上它应该是这样的:

if(answer == null)
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)
  • answer是该类型的对象Answer - a class.
  • AnswerID属于类型的属性long.

奇怪的是,如果你尝试这样的事情:

long myLongValue = null;
Run Code Online (Sandbox Code Playgroud)

编译器会显示错误:

Connot convert null to long ...
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:为什么我没有得到一个编译错误,当我试图来比较long typenull

EDITED

这个问题不是关于nullable类型的.

我问为什么.NET允许我将长变量与null进行比较.我在谈论long type而不是.long? type

Cod*_*ter 31

正如@Tim指出的那样,您不会因以下代码而出错:

long foo = 42;

if (foo == null) { }
Run Code Online (Sandbox Code Playgroud)

你会得到一个警告:

表达式的结果始终为"false",因为"long"类型的值永远不会等于"long"类型的"null".

由于在C#语言规范中定义的提升运算符,这给出了警告而不是错误:

提升的运算符允许在非可空值类型上运行的预定义和用户定义的运算符也可以与这些类型的可空形式一起使用.[...]对于平等运营商

==  !=
Run Code Online (Sandbox Code Playgroud)

如果操作数类型都是非可空值类型并且结果类型是bool,则存在提升形式的运算符.提升形式是通过添加一个?每个操作数类型的修饰符.提升的运算符认为两个空值相等,并且空值不等于任何非空值.如果两个操作数都为非null,则提升的运算符将解包操作数并应用基础运算符以生成bool结果.

在这种情况下,"底层运算符"是预定义值类型long==运算符:

对于预定义的值类型,如果操作数的值相等,则相等运算符(==)返回true,否则返回false.

因为foo是隐式转换的("对非可空值类型进行操作的预定义隐式转换也可以与这些类型的可空形式一起使用.")并且null文本也被隐式转换("从空文本存在到任何可空的隐式转换"输入."),表达式:

(long)foo == null
Run Code Online (Sandbox Code Playgroud)

变为:

(long?)foo == (long?)null
Run Code Online (Sandbox Code Playgroud)

其中,由于foo是类型的long,因此总是有一个值,总是返回false甚至不会应用long==运营商.

我不完全确定,但我怀疑这是存在的,以便在没有显式转换的情况下在可空和非可空值之间进行比较:

long? foo = 42;
long bar = 42;

Console.WriteLine(foo == bar); // true

foo = null;
Console.WriteLine(bar == foo); // false
Run Code Online (Sandbox Code Playgroud)

如果这不是由上面指定的语言处理,你会得到"运算符==不能应用于类型的操作数long?long",因为Nullable<T>没有==运算符,并且long没有==运算符接受a long?.

  • @CodeCaster:似乎是原因.但是,我还在等E. Lippert;) (2认同)

Roy*_*tus 8

它将进行编译,它甚至会执行,因为编译器会评估==并提升longto,long?因为这是与==存在的实现最接近的匹配.

这确实不是最好的行为,它有点像VB :-)