.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,如果我将删除泛型定义并且我将尝试将对象强制转换为某个类,则不会调用unbox.any。
也许unbox.any被调用是因为泛型定义,所以在这种情况下unbox.any需要抛出NullReferenceException,因为isinst指令的答案为此转换返回null。见unbox_any。如果您尝试运行此代码,您将看到没有抛出任何异常。
更新
我可以理解unbox_any因为对象类型参数,它尝试在isinst检查后将其强制转换为具体类型。也许仿制药也会影响。
我的问题是,为什么不在unbox.any中抛出异常,如果我们尝试unbox to T的obj为null?
文档说:“如果obj是空引用,则抛出NullReferenceException。”
答案 0 :(得分:4)
unbox是为了让验证者高兴。验证者对于知道类型参数T总是将成为引用类型并不是特别聪明,因此C#编译器会发出这些不必要的取消框。
如果您搜索Unbox_any和IsVerifierReference的Roslyn源代码,您会发现这种情况发生在代码生成器周围的很多地方。
在生成代码时,抖动将知道类型参数是否为引用,并且无论看似不必要的指令如何都应生成合适的代码。