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
.
Primitive data types cannot be null . Only Object data types can be null .
If you have declared the data type of Plate number as long, then obviously its initial value will be '0' and not 'null'. So, if you try to increment, it will run without any issues.
A NULL value in a table is a value in a field that appears to be blank. A field with a NULL value is a field with no value. It is very important to understand that a NULL value is different than a zero value or a field that contains spaces.
The compiler will show you an error: Connot convert null to long ...
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?
.
It will compile and it will even execute because the compiler evaluates the ==
and promotes the long
to long?
because that is the closest match to an ==
implementation that exists.
This is indeed not the best of behaviors, it's kind of like VB :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With