基本上,我想了解C#编译器确定所调用的方法是非虚拟实例方法还是虚拟方法的一般步骤。
这两个解释(CLR via C#第3版,Jeffrey Richter,第4章类型基础)引起了混淆。
对于非虚拟实例方法的调用,JIT编译器会定位与用于进行调用的变量类型相对应的类型对象。
而对于虚拟方法的调用,JIT编译器会在方法中生成一些额外的代码,每次调用该方法时都会执行此代码。此代码将首先查找用于进行调用的变量,然后跟随地址到调用对象。
我创建了一个小测试项目。
虽然Jon Skeet在他的博客文章中解释了程序为什么会产生这些输出,Eric Lippert也在他的博客文章中确认了这一点(请查看评论部分),但我仍然无法弄清楚编译器是如何决定调用的方法是非虚拟实例方法还是虚拟方法。
似乎对于非虚拟实例方法调用,编译器检查用于调用方法的变量的类型,而对于虚拟方法,则检查用于调用方法的变量引用的对象的类型,因此我猜应该有一种方法可以确定方法是非虚拟的还是虚拟的,在决定如何执行方法之前。
这两个解释(CLR via 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)");
}
}
虽然Jon Skeet在他的博客文章中解释了程序为什么会产生这些输出,Eric Lippert也在他的博客文章中确认了这一点(请查看评论部分),但我仍然无法弄清楚编译器是如何决定调用的方法是非虚拟实例方法还是虚拟方法。
似乎对于非虚拟实例方法调用,编译器检查用于调用方法的变量的类型,而对于虚拟方法,则检查用于调用方法的变量引用的对象的类型,因此我猜应该有一种方法可以确定方法是非虚拟的还是虚拟的,在决定如何执行方法之前。
virtual
/override
,非虚拟方法则没有声明。 - dtb