CIL unbox_any instruction - strange behavior

.method public static void Test<class T>(object A_0) cil managed { // Code size 13 (0xd) .maxstack 1 .locals init (!!T V_0) IL_0000: ldarg.0 IL_0001: isinst !!T IL_0006: unbox.any !!T IL_000b: stloc.0 IL_000c: ret } // end of method DemoType::Test 

Same C # code:

 public static void Test<T>(object o) where T : class { T t = o as T; } 

My questions:

  • Why was unbox.any called? if you just do

      var a = father as child 

    the isinst int call will invoke and there will be unbox.any, and if I delete the general definition and I try to apply the (isinst) object to some class, unbox.any will not be called.

  • Perhaps unbox.any was called due to a common definition, so in this case unbox.any needs to throw a NullReferenceException because the response of the isinst instruction returns null for this cast. see unbox_any . And if you try to run this code, you will see that there was no exception.

Update

I can understand unbox_any because of the type parameter of an object and try to apply it to a specific type after checking isinst. Generics may also be affecting.

My question is: why not throw an exception in unbox.any if the obj we are trying to unpack in T is null?

The documentation says: "NullReferenceException is thrown if obj is a null reference."

+5
source share
1 answer

Unbox must support the verifier. The verifier does not particularly understand that a parameter of type T will always be a reference type, so the C # compiler emits unnecessary unnecessary unnecessary files.

If you search the Roslyn source code for Unbox_any and IsVerifierReference, you will see that this happens in several places around the code generator.

Jitter will know when it generates code whether the type parameter is a reference or not, and should generate decent code regardless of what seems like an unnecessary instruction.

+4
source

Source: https://habr.com/ru/post/1238409/


All Articles