为什么 C# 编译器会为 GetType() 方法调用发出 callvirt 指令? [英] Why is the C# compiler emitting a callvirt instruction for a GetType() method call?

查看:21
本文介绍了为什么 C# 编译器会为 GetType() 方法调用发出 callvirt 指令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很想知道为什么会这样.请阅读下面的代码示例以及每个部分下方注释中发出的相应 IL:

I am curious to know why this is happening. Please read the code example below and the corresponding IL that was emitted in comments below each section:

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,这是否会给类型安全带来问题?

Why did the compiler emit a callvirt for the first section but a call for the second section? Is there any reason that the compiler would ever emit a callvirt instruction for a non-virtual method? And if there are cases in which the compiler will emit a callvirt for a non-virtual method does this create problems for type-safety?

推荐答案

只是谨慎行事.

技术上 C# 编译器并不总是使用 callvirt

Technically C# compiler doesn't always use callvirt

对于静态方法 &在值类型上定义的方法,它使用 call.大多数是通过 callvirt IL 指令提供的.

For static methods & methods defined on value types, it uses call. The majority is provided via the callvirt IL instruction.

两者之间的不同之处在于 call 假定用于进行调用的对象"不为空.另一方面,callvirt 检查 not null 并在需要时抛出 NullReferenceException.

The difference that swung the vote between the two is the fact that call assumes the "object being used to make the call" is not null. callvirt on the other hand checks for not null and throws a NullReferenceException if required.

  • 对于静态方法,对象是类型对象,不能为空.值类型同上.因此 call 用于它们 - 更好的性能.
  • 对于其他语言,语言设计者决定使用 callvirt,以便 JIT 编译器验证用于进行调用的对象不为空.即使对于非虚拟实例方法.. 他们更看重安全而不是性能.
  • For static methods, the object is a type object and cannot be null. Ditto for value types. Hence call is used for them - better performance.
  • For the others, the language designers decided to go with callvirt so the JIT compiler verifies that the object being used to make the call is not null. Even for non-virtual instance methods.. they valued safety over performance.

另请参阅:Jeff Richter 在这方面做得更好 - 在他通过 C# 2nd Ed 在 CLR 中的设计类型"一章中

这篇关于为什么 C# 编译器会为 GetType() 方法调用发出 callvirt 指令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆