Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
137 views
in Technique[技术] by (71.8m points)

c# - Why "long value" equals to null is allowed?

When I was debugging a few lines of code and asking me why on earth it wasn't working I have stumbled on this situation ...

if(answer.AnswerID == null) 
{
    // do something
}

When in fact it should be this way:

if(answer == null)
{
    // do something
}
  • answer is an object of the type Answer - a class.
  • AnswerID is a property of type long.

The weird thing is that if you try something like this:

long myLongValue = null;

The compiler will show you an error:

Connot convert null to long ...

So my question is: Why did I not get a compile error when I was trying to compare a long type with null?

EDITED

This question IS NOT about nullable types.

I'm asking WHY .NET allows me to compare a long variable with null. I'm talking about long type and not about long? type.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As @Tim pointed out, you won't get an error for the following code:

long foo = 42;

if (foo == null) { }

You'll get a warning instead:

The result of the expression is always 'false' since a value of type 'long' is never equal to 'null' of type 'long?'.

This gives a warning instead of an error because of lifted operators, defined in the C# language specification as such:

Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. [...] For the equality operators

==  !=

a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. The lifted form is constructed by adding a single ? modifier to each operand type. The lifted operator considers two null values equal, and a null value unequal to any non-null value. If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

The "underlying operator" in this case is the predefined value type long's == operator:

For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise.

Because foo is implicitly converted ("Predefined implicit conversions that operate on non-nullable value types can also be used with nullable forms of those types.") and the null literal is also implicitly converted ("An implicit conversion exists from the null literal to any nullable type."), the expression:

(long)foo == null

Becomes:

(long?)foo == (long?)null

Which, given foo is of type long and thus always has a value, always returns false and won't even apply long's == operator.

I'm not entirely sure, but I suspect this to exist to enable comparison between nullable and non-nullable values without explicit casting:

long? foo = 42;
long bar = 42;

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

foo = null;
Console.WriteLine(bar == foo); // false

If this wasn't handled by the language as specified above, you'd get "Operator == cannot be applied to operands of type long? and long", because Nullable<T> doesn't have an == operator, and long doesn't have an == operator accepting a long?.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...