我很好奇为什么会这样。请阅读下面的代码示例以及每个部分下方的注释中发出的相应IL:
using System;
class Program
{
static void Main()
{
Object o = new Object();
o.GetType();
// L_0001: newobj instance void [mscorlib]System.Object::.ctor()
// L_0006: stloc.0
// L_0007: ldloc.0
// L_0008: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
new Object().GetType();
// L_000e: newobj instance void [mscorlib]System.Object::.ctor()
// L_0013: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
}
}
为什么编译器在第一部分发出
callvirt
,在第二部分发出call
?编译器是否有理由为非虚拟方法发出callvirt
指令?并且在某些情况下,编译器将为非虚拟方法发出callvirt
,这是否会为类型安全性带来问题? 最佳答案
请放心。
从技术上讲,C#编译器并不总是使用callvirt
对于静态方法和在值类型上定义的方法,它使用call
。多数通过callvirt
IL指令提供。
两者之间引起争议的差异是call
假定“用于进行调用的对象”不为null。另一方面,callvirt
检查是否不为null并在需要时抛出NullReferenceException。
call
用于它们-更好的性能。 callvirt
,以便JIT编译器验证用于进行调用的对象不为null。即使对于非虚拟实例方法,他们也重视安全而不是性能。 另请参见:杰夫·里希特(Jeff Richter)在这方面做得更好-在他的CLR第二版“设计类型”一章中