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.