Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

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

1 Answer

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?.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...