The ECMA spec states this about the box
instruction:
Stack transition:
..., val -> ..., obj
...
If typeTok is a generic parameter, the behavior of box instruction depends on the actual type at runtime. If this type [...] is a reference type then
val
is not changed.
What it's saying is that the compiler can assume that it's safe to box
a reference type. So with generics, the compiler has two choices: emit the code that is guaranteed to work regardless of how the generic type is constrained, or optimize the code and omit redundant instructions where it can prove them to be unnecessary.
The Microsoft C# compiler, in general, tends to choose the simpler approach and leave all optimization to the JIT stage. To me, it looks like your example is exactly that: not optimizing something because implementing an optimization takes time, and saving this box
instruction probably has very little value in practice.
C# allows even an unconstrained generic-typed value to be compared to null
, so the compiler must support this general case. The easiest way to implement this general case is to use the box
instruction, which does all the heavy-lifting of handling reference, value and nullable types, correctly pushing either a reference or a null value onto the stack. So the easiest thing for the compiler to do is to issue box
regardless of the constraints, and then compare the value to zero (brtrue
).