CIL unbox_any指令 - 奇怪的行为

时间:2015-12-16 17:30:26

标签: .net clr nullreferenceexception cil il

.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

相同的C#代码是:

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

我的问题是:

  1. 为什么unbox.any被调用?如果你这样做

     var a = father as child 
    

    isinst intruction将调用而不是unbox.any,如果我将删除泛型定义并且我将尝试将对象强制转换为某个类,则不会调用unbox.any。

  2. 也许unbox.any被调用是因为泛型定义,所以在这种情况下unbox.any需要抛出NullReferenceException,因为isinst指令的答案为此转换返回null。见unbox_any。如果您尝试运行此代码,您将看到没有抛出任何异常。

  3. 更新

    我可以理解unbox_any因为对象类型参数,它尝试在isinst检查后将其强制转换为具体类型。也许仿制药也会影响。

    我的问题是,为什么不在unbox.any中抛出异常,如果我们尝试unbox to T的obj为null?

    文档说:“如果obj是空引用,则抛出NullReferenceException。”

1 个答案:

答案 0 :(得分:4)

unbox是为了让验证者高兴。验证者对于知道类型参数T总是将成为引用类型并不是特别聪明,因此C#编译器会发出这些不必要的取消框。

如果您搜索Unbox_any和IsVerifierReference的Roslyn源代码,您会发现这种情况发生在代码生成器周围的很多地方。

在生成代码时,抖动将知道类型参数是否为引用,并且无论看似不必要的指令如何都应生成合适的代码。