多态如何在C#中使用未定义的中间类型?

在下面的代码中,我a.Generate(v)期望调用a.Generate(v)会导致调用V.Visit(A a) ,因为当调用Generate时this是A类型的Hoewever,看来this被认为是Inter

是否有可能在没有在AB显式实现(相同)方法而只在共享基类上实现预期的行为? 如果是这样,怎么能实现呢?

 using System; using System.Diagnostics; namespace Test { class Base {} class Inter: Base { public virtual void Generate(V v) { // `Visit(Base b)` and not `Visit(A a)` is called when calling // A.Generate(v). Why? v.Visit(this); } } class A: Inter {} class B: Inter {} class V { public void Visit(Base b) { throw new NotSupportedException(); } public void Visit(A a) { Trace.WriteLine("a"); } public void Visit(B b) { Trace.WriteLine("b"); } } class Program { static void Main() { V v = new V(); A a = new A(); B b = new B(); a.Generate(v); b.Generate(v); } } } 

编辑在答案中建议上面的代码不是多态的。 我会反对。 V.Visit是多态的 。

您期望调用v.Visit(this)来确定基于vthis运行时类型调用Visit哪个重载。

具有该function的语言称为“双虚拟调度”语言。 (或者,如果考虑两个以上的东西,它们被称为“多个虚拟调度”语言,或“多方法”语言。)

C#不是双虚拟调度语言; 在编译时进行调度决策时,它是一种单虚拟调度语言。 也就是说,决定选择哪个重载是基于接收器运行时类型,而是参数的编译时类型。

现在,在您的情况下,C#不使用单个虚拟调度,因为对Visit的调用甚至不是虚拟调用! 对Generate的调用是虚拟调用这一事实完全无关紧要,并且Visit过载这一事实也无关紧要。 对虚拟 Visit的调度是非虚拟的 ,因此调度逻辑完全基于接收器的编译时类型v和参数this 。 由于已知接收器是V型,并且已知参数是Inter类型,因此重载决策必须选择仅给出该信息的最佳匹配。 它不能选择带有ABVisit版本,因为它们的派生类型比已知的参数类型Inter 。 它必须选择带有较少派生forms参数类型Base的重载。

如果您希望在C#中实现双虚拟调度,有两种标准方法可以实现。 首先,你可以使用dynamic ; 使用dynamic ,分析在运行时使用运行时类型执行。 只需将接收器和参数转换为dynamic ,编译器就会为您处理它。 但这会带来显着的性能成本。

第二种标准方法是使用访客模式 ,您可以通过在互联网上搜索它来找到它。 我怀疑你的方法名称是否已经尝试实现访问者模式; 这不是正确的方法。

这不是多态代码,多态代码具有动态绑定,它决定了在运行时调用哪个方法。 两个对象必须具有类似的基类,并使用虚方法来执行此动态绑定。 现在你的绑定是静态的,并在编译时确定。

问题是Generate方法是在Iter类中定义的。 因此,当调用Generate方法时,它会将引用传递给Iter

如果要传入AB ,请Generate虚拟并在AB级别覆盖它以传入正确转换的值。

你究竟期待什么?

 public void Visit(Base b) { Trace.WriteLine(b.GetType().Name); } 

不知何故,编译器为v.Visit(this)编译了一个代码版本。 根据传递的参数的实际tpye,它无法为每个调用实例编译不同的版本。

在多态设计中,Inter和它的每个派生类都负责做“个人”的事情。

 public void Visit(Base b) { b.VisitedBy(v); } 

其中VisitedBy()是一个虚函数。