In IL on this level, null
is just null
. The compiler knew it was null
because that is what you wrote, as such the compiler does not need to call the cast operator at all. Casting null
to an object will just yield null
.
So this is a compile-time "optimization" or simplification if you will.
Since this is legal, to cast null
to another object type, there is neither a warning nor an error reported from this.
Note that apparently the compiler will not do this even thought it may be able to verify that the value being cast is indeed guaranteed to be null
, if it isn't a literal.
Your example:
void Main()
{
var s = (string)null;
GC.KeepAlive(s);
}
IL:
IL_0000: ldnull
IL_0001: stloc.0 // s
IL_0002: ldloc.0 // s
IL_0003: call System.GC.KeepAlive
(I added the call to GC.KeepAlive
to avoid the compiler dropping the entire variable due to it not being used anywhere.)
If I stuff the null
into an object first, with no possibility of it changing:
void Main()
{
object o = null;
var s = (string)o;
GC.KeepAlive(s);
}
IL:
IL_0000: ldnull
IL_0001: stloc.0 // o
IL_0002: ldloc.0 // o
IL_0003: castclass System.String
IL_0008: stloc.1 // s
IL_0009: ldloc.1 // s
IL_000A: call System.GC.KeepAlive