c#如何区分实例方法和虚方法

Mic*_*ael 4 .net c# clr virtual-functions

所以基本上我想了解C#编译器用来确定被调用的方法是非虚拟实例方法还是虚方法的一般步骤.

混淆来自这两个解释(CLR通过C#第3版,Jeffrey Richter,第4章类型基础)

调用非虚拟实例方法时,JIT编译器将查找与用于进行调用的变量类型对应的类型对​​象

对于虚方法调用

在调用虚拟实例方法时,JIT编译器会在方法中生成一些额外的代码,每次调用该方法时都会执行该代码.此代码将首先查看用于进行调用的变量,然后将地址跟随调用对象

我创建了小型测试项目

class Program
    {
        static void Main(string[] args)
        {
            Parent p = new Derived();
            p.Foo(10); // Outputs Derived.Foo(int x)

            Derived d = new Derived();
            d.Foo(10); // Outputs Derived.Foo(double y)
        }
    }

    internal class Parent
    {
        public virtual void Foo(int x)
        {
            Console.WriteLine("Parent.Foo(int x");
        }
    }

    internal class Derived: Parent
    {
        public override void Foo(int x)
        {
            Console.WriteLine("Derived.Foo(int x)");
        }

        public void Foo(double y)
        {
            Console.WriteLine("Derived.Foo(double y)");
        }
    }
Run Code Online (Sandbox Code Playgroud)

虽然Jon Skeet有一篇博客文章解释了为什么程序会产生这些输出,而Eric Lippert在他的博客文章(查看评论部分)中确认了这一点,我仍然无法弄清楚编译器如何判断被调用的方法是否是非虚拟的实例方法或虚方法.

似乎对于非虚拟实例方法调用,编译器检查用于调用方法的变量的类型,以及虚拟方法 - 由用于调用方法的变量引用的对象类型,所以我猜,在决定如何执行该方法之前,应该有一些方法来确定方法是非虚拟的还是虚拟的.

jas*_*son 10

在决定如何执行方法之前,应该有一些方法来确定方法是非虚拟的还是虚拟的.

JIT编译器与C#编译器不同.到执行到达JIT编译器时,C#编译器已经决定是否发出虚方法调用或非虚方法调用.里希特书中唯一告诉你的是JIT编译器调用虚拟方法和非虚方法的不同之处.它没有告诉您C#编译器如何决定是否发出虚拟或非虚方法调用.

通常,为此,您需要查看语言规范.如果编译器将程序代码解释为调用的方法是虚拟的,则它将发出虚拟调用.否则,它不会.在这种特殊情况下语言的规则,以及Jon的帖子,指示编译器Derived.Foo(double)在第二次调用中发出非虚方法调用.这是因为在这种情况下,编译器将程序代码(再次基于语言规范)解释为要调用Derived.Foo(double).JIT不知道任何这个,它只是看到IL执行非虚拟调用,Derived.Foo(double)引用d作为隐式this参数和10第一个显式参数.