Why can I check generic for null when it may be invalid or cannot be an object?
The question is unconvincing; the value of any generic type expression will always be either an object or a null reference at run time. I think you wanted to ask:
Why can I check what is common to null when its runtime type cannot be either a null value type or a reference type?
The C # specification ensures that comparing equality with literal zero is legal in section 7.6.10, which I quote here for your convenience:
If an operand of type T is compared to NULL and the runtime type T is value type, the result of the comparison is false. [...] The construction x == null allowed, even if T can represent the type of value, and the result is simply defined as false when T is the type of value.
Please note that there is a small mistake; the last sentence should end with "type with a zero value".
I am never sure if I really answered the question βwhy?β. The question is satisfactory or not. If this is not satisfactory, try asking a more specific question.
Should the compiler notify me that I am using null?
Not. Why do you think the compiler should warn you about using the language function correctly?
Does it use box-to-object conversion to perform a check for null here?
Well, this is a bit of a difficult point. On the one hand, section 7.6.10 states:
The predefined reference type equality operators never give rise to boxing operations for their operands. It would be pointless to perform such boxing operations, since links to newly selected nested instances will necessarily be different from all other links.
However, when we generate IL to compare the total T with NULL, we certainly do generate the T field, the load is null, and the comparison. Jitter can be smart enough to rule out the actual distribution of memory in a box; if T is a reference type, then it does not need a box, if it is a type of values ββwith a null value, then it could be turned into a call to check the HasValue property, and if it is a value type that is not null, then boxing and checking can be turned into a simple generation of "false". I don't know exactly what the various jit compiler implementations actually do; if you're interested, check and see!