C#如何在基地的基础上调用方法?

时间:2009-12-04 00:29:30

标签: c#

假设A类继承自B类,而B继承自C类。现在假设在A中定义了一个虚方法void f(),它在B和C中都被重写。从任何一个调用Bf() A中的方法可以通过简单地使用base.f()来完成。如何从A?

中的方法调用C.f()

9 个答案:

答案 0 :(得分:11)

通常,通过重写一个类,您接受它提供了所需的接口和一些行为。 A不应该知道它的超级超级,除非它的超类以某种方式明确暴露。这实际上是可取的,因为当您继承B时,您不需要知道C是如何实现的。您甚至不应该知道C涉及。

如果b的f()调用base.f(),则base.f()只需要调用自己的base.f()就可以了。如果没有,那么自己做的唯一方法就是通过基于Reflection的侵入式方法。如果你发现自己需要这样做,你的设计可能会出错(违反了得墨忒耳定律)。

答案 1 :(得分:3)

您可以通过反思或IL代码生成。除此之外,你不能,你真的不应该,这听起来不像是好的设计。

当您在OOP中覆盖方法时,基本上说“对于这种类型,此方法将替换旧方法”,并且必要时(通常是)可以调用替换(覆盖)方法。

但是,你不能直接跳过一个关卡,除非你采用反射或IL技巧,并且有充分的理由。如果中间类允许您跳过此方法调用,则应该为其添加一个可以使用的特殊方法。这是“难”做的原因是你通常不应该这样做,你应该总是进入下一级别,以便它可以保持控制。

答案 2 :(得分:1)

这可以通过反思来完成。您获取当前类的Type,使用它来获取父类型,然后获取父类型的父类型。

该语言不直接支持的原因是它打破了继承的抽象模型。它与传统的面向对象设计并不完全兼容。

答案 3 :(得分:1)

我认为你的意思是从C?中的方法调用A.f()。

简短回答:你不能

但是,如果你可以控制B,你可以向B添加一个方法来明确地调用它的基础:

protected void BaseF()
{
    base.f();
}

然后从C

调用该方法

答案 4 :(得分:0)

试试这个:

C c = this;
c.f();

打印“C”:

public static void Main()
{
 A o = new A();
 Console.WriteLine(o.f());
}

class C
{
 public virtual string f()
 {
  return "C";
 }
}

class B : C
{
 public virtual string f()
 {
  return "B";
 }
}

class A : B
{
 public virtual string f()
 {
     C c = this;
     return c.f();
 }
}

答案 5 :(得分:0)

从C中的函数,你可以调用base.f(),,这就是你应该做的。如果Bf()(你正在实际调用的那个)选择也调用base.f(),那么就可以达到你想要的效果,但完全取决于B的实现,不管是否发生了。

您可以尝试将C转换为A并调用f(),如下所示:

public class C : B {
    public override f() {
        ((A) this).f();
    }
}

但问题是C不知道f()在哪里被声明 - 它只知道在B中有一个可以被覆盖的实现,C不知道A存在。上面的示例实际上是一段糟糕的代码,如果A没有实现f(),则会产生编译时错误。

答案 6 :(得分:0)

使用new而不是override是一种方式(该函数不需要虚拟使用new,尽管它可以是。)

这可能会给你一些其他问题。如果您将MyClass向上投射到MyBaseClass,它将使用该函数的MyBaseClass版本。

private void Form1_Load(object sender, EventArgs e)
{

    var mc = new MyClass();

    mc.Foo();
    ((MyBaseClass) mc).Foo();
}


public class MyBaseClass
{           
    public virtual void Foo ()
    {
        Console.WriteLine("Calling from MyBaseClass");
    }
}

public class MyClass : MyBaseClass
{

    new public void Foo ()
    {
        Console.WriteLine("Calling from MyClass");
    }
}

你得到的输出是:

Calling from MyClass
Calling from MyBaseClass

答案 7 :(得分:0)

正如之前评论的那样,Virtual永远不会以这种方式被覆盖,你必须使用'new'而不是'override'。

以下是使用您的班级名称的示例:

这不是一个好习惯,因为它会变得非常混乱并且会破坏大部分预期的继承行为,而'new'关键字旨在强制将新的接口项强制转换为不打算被覆盖的类。

干杯,  杰森

    class Program
{
    static void Main(string[] args)
    {
        C c = new C();
        A a = new A();
        a.DoThis();
        Console.ReadKey();
    }
}

public class C
{
    public virtual void DoThis() {
        Console.WriteLine("In C"); }
}

public class B : C
{
    public new void DoThis()
    {
        Console.WriteLine("In B");
    }
}

public class A : B
{
    public new void DoThis()
    {
        Console.WriteLine("In A..");
        ((C) this).DoThis();
    }
}

答案 8 :(得分:0)

这似乎是一个设计问题。

你有几个选择:

  1. 取大部分A.DoThis(),并将其移动到另一个适当的方法(受保护的?)(DoThat()?)。现在,您可以直接调用它。
  2. 拆分对象,并考虑使用组合而不是继承来重用行为。