我正在调查这段代码的执行情况:

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

等效的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

基于这个答案(unnecessary unbox_any),有谁能解释抖动在这里的确切逻辑是什么;抖动在这种特定情况下究竟是如何决定忽略“unbox_any”指令的(理论上,根据msdn,当isinst指令产生null时,应该抛出一个nullreferenceexception,但这在实践中是不会发生的!)
更新
根据usr answer和hans comment,如果obj是引用类型,则将调用castclass,因此不会调用nre。
但接下来的案子呢?
static void Test<T>(object o) where T : new()
    {
        var nullable = o as int?;
        if (nullable != null)
            //do something
    }

Test<int?>(null);

以及等效的IL代码(部分):
IL_0001:  ldarg.0
IL_0002:  isinst     valuetype [mscorlib]System.Nullable`1<int32>
IL_0007:  unbox.any  valuetype [mscorlib]System.Nullable`1<int32>
IL_000c:  stloc.0
IL_000d:  ldloca.s   nullable
IL_000f:  call       instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0014:  stloc.1
IL_0015:  ldloc.1
IL_0016:  brfalse.s  IL_0024

在这种情况下,它的值类型为何不抛出nre?

最佳答案

应用于引用类型时,unbox.any指令的效果与castclass typetok相同。
T被约束为引用类型。在这种情况下,此指令不抛出nre。jit不会“忽略”它,而是按照指定的方式执行它。不允许jit忽略指令。
文件中有声明
如果obj是空引用,则引发nullreferenceexception。
这是误导,因为它只适用于价值类型。我引用的第一句话毫不含糊。

07-24 20:34