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