.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;
}

我的问题是:
  • 为什么调用unbox.any?如果你只是做
     var a = father as child
    

    isinst intruction将调用并且没有unbox.any,并且如果我将删除泛型定义并且尝试将对象强制转换(isinst)到某个类,则不会调用unbox.any。
  • 可能因为泛型定义而调用了unbox.any,因此在这种情况下,unbox.any需要抛出NullReferenceException,因为isinst指令的答案为此转换返回null。参见unbox_any。而且,如果您尝试运行此代码,您将看到未引发任何异常。

  • 更新

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

    我的问题是,如果我们尝试将其拆箱到T的obj为null,为什么不在unbox.any中引发异常?

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

    最佳答案

    取消包装是为了使验证者满意。对于知道类型参数T始终是引用类型的情况,验证程序不是特别聪明,因此C#编译器会发出这些原本不必要的取消框。

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

    抖动会在生成代码时知道type参数是否为引用,并且无论看上去似乎不必要的指令如何,都应该生成体面的代码。

    09-03 23:54