我正在调查此 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
基于这个答案(不必要的 unbox_any https://stackoverflow.com/a/34321727/986184),谁能向我解释一下 Jitter 在这里执行的确切逻辑是什么?在这种特定情况下,抖动到底如何决定忽略“unbox_any”指令(理论上,根据msdn https://technet.microsoft.com/sr-latn-rs/library/system.reflection.emit.opcodes.unbox_any,当 isinst 指令产生 null 时,应该抛出 NullReferenceException,但这在实践中不会发生!)
Update
根据 usr 的回答和 Hans 的评论,如果对象是一个引用类型,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。
这是误导性的,因为它仅适用于值类型。我引用的第一句话是明确的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)