【问题标题】:CIL unbox_any instruction - strange behaviorCIL unbox_any 指令 - 奇怪的行为
【发布时间】:2015-12-20 03:47:09
【问题描述】:
.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 指令将调用并且没有 unbox.any,如果我将删除通用定义并尝试将对象强制转换 (isinst) 到某个类,则不会调用 unbox.any。

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

更新

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

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

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

【问题讨论】:

  • 你能详细说明什么如此奇怪吗?对我来说这是有道理的。在第 (2) 点中,您也没有提出任何问题。
  • @usr 首先,我想验证为什么 unbox_any 被调用。打电话给他们两个是什么意思? (isinst 和 unbox_any) 其次,更重要的是,如果传递给 unbox_any 的 obj 为 null,为什么不引发异常?

标签: .net clr nullreferenceexception cil il


【解决方案1】:

拆箱是为了让验证者满意。验证器并不特别聪明地知道类型参数 T 始终是引用类型,因此 C# 编译器会发出这些否则不必要的拆箱。

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

jitter 会在生成代码时知道类型参数是否是引用,并且应该生成像样的代码,而不管看似不必要的指令如何。

【讨论】:

  • 如果有人对此感兴趣,我建议查看here 以获取完整图片
猜你喜欢
  • 1970-01-01
  • 2012-01-12
  • 2011-04-02
  • 2017-01-23
  • 2013-07-03
  • 2013-06-22
  • 1970-01-01
  • 1970-01-01
  • 2012-04-05
相关资源
最近更新 更多