[英]Dynamic Dispatch - Template Method in C#
我不明白为什么打印以下输出。
静态类型为Base并调用print()并导致控制台输出:
静态类型为Sub并调用print()并导致控制台输出:
为什么在这里叫Base.B而不叫Sub.B?
静态类型为Sub,对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"); }
}
区别在于从每个位置调用每种方法的方式不同,归结为new
和virtual
/ 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.