Why doesn't incrementing Nullable<int> throw an exception?
You're observing the effects of a lifted operator.
From section 7.3.7 of the C# 5 specification:
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. Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:
- For the unary operators
+ ++ - -- ! ~
a lifted form of an operator exists if the operand and result types are both non-nullable value types. The lifted form is constructed by adding a single?
modifier to the operand and result types. The lifted operator produces a null value if the operand is null. Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.
So basically, a++
in this case is an expression with a result of null
(as an int?
) and the variable is left untouched.
When you call
Console.WriteLine(a);
that's being boxed into object
, which converts it to a null reference, which is printed as an empty line.
Jon's answer is correct but I would add some additional notes.
Why does
Console.WriteLine(null)
give a compilation error?
There are 19 overloads of Console.WriteLine
and three of them are applicable to a null
: the one that takes a string
, the one that takes a char[]
and the one that takes an object
. C# cannot determine which of these three you mean, so it gives an error. Console.WriteLine((object)null)
would be legal because now it is clear.
why does
Console.WriteLine(a)
write an empty line?
a
is a null int?
. Overload resolution chooses the object
version of the method, so the int?
is boxed to a null reference. So this is basically the same as Console.WriteLine((object)null)
, which writes an empty line.
Why there is not
NullReferenceException
on the increment?
Where's the null reference that you are worried about? a
is a null int?
which is not a reference type to begin with! Remember, nullable value types are value types, not reference types, so don't expect them to have reference semantics unless they are boxed to a reference type. There is no boxing in the addition.