繁体   English   中英

动态调度-C#中的模板方法

[英]Dynamic Dispatch - Template Method in C#

我不明白为什么打印以下输出。

静态类型为Base并调用print()并导致控制台输出:

  • Sub1.A
  • Base.B

静态类型为Sub并调用print()并导致控制台输出:

  • Sub1.A
  • Base.B

为什么在这里叫Base.B而不叫Sub.B?

静态类型为Sub,对B()的调用导致控制台输出:

  • Sub1.B

Sub上的隐藏函数B()在程序中被调用。 但是如果我用print()调用它就不会。

static void Main(string[] args)
{                
            Base b = new Sub();
            Sub s =  b as Sub;

            b.print(); //See first paragraph with 2 bullet points
            s.print(); //See second paragraph bullet points
            s.B(); //See third paragraph with bullet points

}

public class Base
{
        public Base() {}

        public void print()
        {
            A();
            B();
        }

        public virtual void A() { Console.WriteLine("Base.A"); }

        public void B() { Console.WriteLine("Base.B"); }
}

public class Sub : Base
{
        public Sub()  { }

        public override void A() { Console.WriteLine("Sub1.A"); }

        public new void B() { Console.WriteLine("Sub1.B"); }
}

区别在于从每个位置调用每种方法的方式不同,归结为newvirtual / override之间的区别。

首先是理论,对这两个关键字的解释过于简单:

  • new只是在派生类中定义了另一个方法,该方法与“隐藏”它的基类中现有方法的名称相同。 根据用于调用该方法的引用的类型,在编译时选择要调用的方法(基本方法还是派生方法)。
  • virtual表示方法可以在派生类中具有替代实现,在这种情况下,应改用它。 在此,根据实际对象的类型在运行时进行选择。

现在将其应用于您的案例。 这里所有对A调用都是完全相同的,因为它是虚拟的,唯一的实例是Sub类型。 动态调度会完成它的工作,这将导致您发现对Sub.B的调用。

但是对B的调用在两个地方。 一个直接在print方法中,另一个直接在main 由于B不是virtual因此它使用静态分派和其引用的编译时类型来确定调用站点。 来自main的一个很容易Sub.B为什么要使用Sub.B 但是, print方法中的另一个不使用相同的引用,它们隐式使用this指针调用同一类中的实例方法。 这完全等同于编写以下代码:

public void print()
{
    this.A();
    this.B();
}

因此,对B的调用完全取决于this的编译时类型,在这种情况下,它是Base (因为它是在该类中编写的)。 因此, Base.B调用了Base.B

先前的print调用来自另一种类型的变量的事实在这里是不相关的,因为它仅用于确定采用哪种print实现(这里只有一个),但是方法本身所做的任何操作都超出了此范围,并且因此不影响其行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM