【发布时间】:2016-03-26 18:14:51
【问题描述】:
我正在调查这段 C# 代码的执行情况:
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),谁能向我解释一下 Jitter 在这里做什么的确切逻辑;在这种特定情况下,Jitter 究竟是如何决定忽略 'unbox_any' 指令的(理论上,根据msdn,当 isinst 指令产生 null 时应该抛出 NullReferenceException,但实际上不会发生这种情况!)
更新
根据 usr 的回答和 Hans 的评论,如果 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?
【问题讨论】:
-
public static void Test<T>(T o) where T : class因为从未抛出运行时异常。 -
@HamletHakobyan 你在实践中是对的。但它应该根据 msdn(请参阅 msdn 链接)。没有抛出异常的原因是因为抖动发出 unbox_any 指令(参见其他答案链接)。
-
"当应用于引用类型时,unbox.any 指令与 castclass typeTok 具有相同的效果。如果操作数 typeTok 是泛型类型参数,则运行时行为是由为该泛型类型参数指定的类型确定。” 在文档中的哪个位置指定了 NRE?
-
@YuvalItzchakov 我看到了,但我想确定确切的逻辑。那么,类型的抖动检查,如果它是引用类型,unbox_any 会被忽略吗?
-
如果您需要证明,只需 look at the source。注意它在
!eeIsValueClass(resolvedToken.hClass)上的快捷方式
标签: c# .net optimization clr jitter