And*_*are 28 c# compiler-construction il type-safety
我很想知道为什么会这样.请阅读下面的代码示例以及每个部分下面的注释中发出的相应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()
}
}
Run Code Online (Sandbox Code Playgroud)
为什么编译器callvirt为第一部分发出a 而call第二部分发出a ?是否有任何理由编译器会发出callvirt非虚方法的指令?如果在某些情况下编译器将callvirt为非虚拟方法发出一个,这会产生类型安全问题吗?
Dus*_*ell 28
请参阅Eric Gunnerson撰写的这篇旧博客文章.
这是帖子的文字:
为什么C#总是使用callvirt?
这个问题出现在一个内部的C#别名上,我认为答案是普遍感兴趣的.这是假设答案是正确的 - 已经有一段时间了.
.NET IL语言提供call和callvirt指令,callvirt用于调用虚函数.但是如果你仔细查看C#生成的代码,即使在没有涉及虚函数的情况下,你也会看到它生成一个"callvirt".为什么这样做?
我回过头来看过我的语言设计笔记,他们非常清楚地说明我们决定在12/13/1999使用callvirt.不幸的是,他们没有抓住我们这样做的理由,所以我将不得不离开我的记忆.
我们收到了某人的报告(很可能是一个使用C#的.NET组(当时认为它还没有命名为C#))谁编写了一个在空指针上调用方法的代码,但是他们没有得到一个例外,因为该方法没有访问任何字段(即"this"为null,但方法中没有使用它).那个方法然后调用另一个方法,它确实使用了这一点并引发了一个异常,随后出现了一些令人头疼的问题.在他们弄清楚之后,他们给我们发了一张关于它的说明.
我们认为能够在null实例上调用方法有点奇怪.Peter Golde做了一些测试,看看总是使用callvirt的性能影响是什么,它足够小,我们决定做出改变.
Gis*_*shu 22
只是玩得安全.
从技术上讲,C#编译器并不总是使用callvirt
对于在值类型上定义的静态方法和方法,它使用call.大多数是通过callvirtIL指令提供的.
摆动两者之间投票的区别在于call假设"用于进行调用的对象"不为空.callvirt另一方面,检查not null并在需要时抛出NullReferenceException.
call用于它们 - 更好的性能.callvirt因此JIT编译器会验证用于进行调用的对象是否为空.即使对于非虚拟实例方法,他们也重视安全性而非性能.另请参阅:Jeff Richter在此处做得更好 - 在CLR中的"设计类型"一章中通过C#2nd Ed