非虚拟方法解析-为什么会发生 [英] Non virtual method resolution - why is this happening

查看:113
本文介绍了非虚拟方法解析-为什么会发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C#中,我对如何解析非虚拟方法的理解是,它取决于变量的类型(而不是实例的类型).

My understanding (in C#) of how non-virtual methods are resolved is that it is dependent upon the type of the variable (and not the type of instance).

看看下面的代码.

class Program
{
    static void Main(string[] args)
    {
        Sedan vehicle = new Sedan();
        vehicle.Drive();
        vehicle.Accelerate();
    }
}

abstract class VehicleBase
{
    public void Drive()
    {
        ShiftIntoGear();
        Accelerate();
        Steer();
    }

    protected abstract void ShiftIntoGear();
    protected abstract void Steer();

    public void Accelerate()
    {
        Console.WriteLine("VehicleBase.Accelerate");
    }
}

class Sedan : VehicleBase
{
    protected override void ShiftIntoGear()
    {
        Console.WriteLine("Sedan.ShiftIntoGear");
    }

    protected override void Steer()
    {
        Console.WriteLine("Sedan.Steer");
    }

    public new void Accelerate()
    {
        Console.WriteLine("Sedan.Accelerate");
    }
}

控制台窗口显示以下内容:

The Console Windows shows the following:

Sedan.ShiftIntoGear
VehicleBase.Accelerate
Sedan.Steer
Sedan.Accelerate

这对我来说没有意义,我相信这会让很多人陷入困境.如果现在将变量车辆声明为VehicleBase类型,则会得到

This doesn't make sense to me and I believe would throw many folks for a loop. If you now declare variable vehicle to be of type VehicleBase you get

Sedan.ShiftIntoGear
VehicleBase.Accelerate
Sedan.Steer
VehicleBase.Accelerate

在前面的案例中,这也是我所期望的,因为Accelerate方法不是虚拟的.

Which is what I'd expect in the previous case as well because the method Accelerate is non-virtual.

在上一个输出中,(将变量车辆键入Sedan,我希望可以调用Sedan.Accelerate而不是VehicleBase.Accelerate.就目前而言,取决于您从(从内部调用)的位置班级或从外部)的行为正在改变.

In the previous output, (with the variable vehicle typed as a Sedan, I'd expect the Sedan.Accelerate to be called instead of VehicleBase.Accelerate. As it stands now, depending on where you call it from (from within the class or from outside) the behavior is changing.

在我看来,重新引入的方法的重载解决规则优先,但是我很难相信这是正确的/预期的行为.

It seems to me that the overload resolution rule(s) for re-introduced methods is taking precedence but I have a hard time believing that this is correct/expected behavior.

推荐答案

非虚拟方法在编译时根据表达式的类型进行解析,并且调用目标在编译时固定.编译器会在调用的源代码上下文中的编译时在可用的符号信息中查找方法名称,并发出调用指令以调用能够找到的非虚拟方法.实例的实际类型是什么都没有关系,调用总是转到在编译时从静态类型信息中找出的非虚拟方法.

Non-virtual methods are resolved according to the type of the expression at compile time, and the call destination is fixed at compile time. The compiler looks up the method name in the symbol info available at compile time in the source code context of the call, and emits a call instruction to call the non-virtual method that it was able to find. It doesn't matter what the actual type of the instance is, the call always goes to the non-virtual method figured out at compile time from static type info.

这就是为什么对Accelerate的调用在Main上下文中转到Sedan.Accelerate,而在VehicleBase.Drive上下文中转到VehicleBase.Accelerate:

Here is why the call to Accelerate goes to Sedan.Accelerate in the context of Main, but goes to VehicleBase.Accelerate in the context of the VehicleBase.Drive:

Main函数的主体中,您声明了一个Sedan类型的变量,然后使用该变量进行方法调用.编译器在用于进行调用的变量的类型中查找名为"Accelerate"的方法,键入Sedan,然后找到Sedan.Accelerate.

In the body of your Main function, you have declared a variable of type Sedan, and you make the method call using that variable. The compiler looks for the method named "Accelerate" in the type of the variable used to make the call, type Sedan, and finds Sedan.Accelerate.

在方法VehicleBase.Drive中,自我"的编译时类型为VehicleBase.这是编译器在此源代码上下文中可以看到的唯一类型,因此即使运行时对象实例的类型实际上是Sedan,在"VehicleBase.Drive"中对Accelerate的调用也总是转到VehicleBase.Accelerate.

Inside the method VehicleBase.Drive, the compile-time type of "self" is VehicleBase. This is the only type the compiler can see in this source code context, so that call to Accelerate in 'VehicleBase.Drive' will always go to VehicleBase.Accelerate, even if the runtime object instance's type is actually Sedan.

在以Sedan类型声明的方法的主体中,编译器将通过首先查看Sedan类型的方法,然后查看VehicleBase类型(如果没有)来解决非虚拟方法调用在Sedan中找到了匹配项.

In the body of a method declared in the Sedan type, the compiler would resolve the non-virtual method call by looking in the methods of the Sedan type first, then looking at the VehicleBase type if no match were found in Sedan.

如果要根据实际对象实例类型更改调用目标,则必须使用虚拟方法.使用虚拟方法还将提供更加一致的执行结果,因为调用将始终转到由对象实例在运行时确定的最具体的实现.

If you want the call destination to change based on the actual object instance type, you must use virtual methods. Using virtual methods will also give much more consistent execution results, since the call will always go to the most specific implementation determined by the object instance at runtime.

非虚拟方法调用目标是根据编译时类型选择的,并且不了解运行时.在运行时根据实例类型选择虚拟方法的调用目标.

Non-virtual method call destinations are selected according to the compile-time type, with no awareness of runtime. Virtual method call destinations are selected according to the instance type at runtime.

这篇关于非虚拟方法解析-为什么会发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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