C#如何在基的基中调用方法?

C#如何在基的基中调用方法?,c#,C#,假设类A从类B继承,而类B又从类C继承。现在假设在A中定义了一个虚拟方法void f(),它在B和C中都被重写。从A中的任何方法调用B.f()只需使用base.f()即可。从中的方法调用C.f()怎么样?试试以下方法: C c = this; c.f(); 这将打印“C”: 这可以通过反射来实现。获取当前类的类型,使用该类型获取父类型,然后获取父类型的父类型 该语言不直接支持它的原因是它打破了继承的抽象模型。它与传统的面向对象设计并不兼容。您可以通过反射或IL代码生成。除此之外,你不能,你真的

假设类A从类B继承,而类B又从类C继承。现在假设在A中定义了一个虚拟方法void f(),它在B和C中都被重写。从A中的任何方法调用B.f()只需使用base.f()即可。从中的方法调用C.f()怎么样?

试试以下方法:

C c = this;
c.f();
这将打印“C”:


这可以通过反射来实现。获取当前类的类型,使用该类型获取父类型,然后获取父类型的父类型


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

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

当您在OOP中重写一个方法时,您基本上会说“对于这种类型,此方法将替换旧方法”,并规定您可以在必要时(通常是这样)调用替换的(重写的)方法


然而,你不能直接跳过一个关卡,除非你求助于反思或IL欺骗,这是有充分理由的。如果中间类允许您跳过此方法调用,则应向其添加一个可以使用的特殊方法。之所以“很难”做到这一点,是因为您通常不应该这样做,您应该始终转到下一个级别,以便它能够保持控制。

我猜您的意思是从C中的方法调用A.f()

简单回答:你不能

但是,如果您可以控制B,则可以向B添加一个方法以显式调用其基:

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

然后从C调用该方法通常,通过重写一个类,您可以接受它提供了您想要的接口和一些行为。A不应该知道它的超类,除非它的超类以某种方式显式地公开。这实际上是可取的,因为当您使用子类B时,您不需要知道C是如何实现的。您甚至不应该知道C是如何实现的


如果b的f()调用base.f(),a的base.f()只需要调用它自己的base.f()就可以了。如果没有,唯一的方法就是通过基于反射的侵入式方法。如果您发现自己需要这样做,那么您的设计可能有错误(例如违反了德米特定律)。

从C中的函数中,您可以调用base.f(),这就是您应该做的。如果B.f()(这是您正在有效地调用的)选择同时调用base.f(),那么这就实现了您想要的,但这完全取决于B的实现,取决于是否会发生

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

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

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

使用
new
而不是
重写
是一种方法(虽然可以使用
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

如前所述,虚拟机永远不能以这种方式重写,您必须使用“new”而不是“override”

下面是一个使用类名的示例:

这不是一个好的做法,因为它会变得非常混乱,并破坏许多预期的继承行为,“new”关键字旨在将新接口项强制到不打算被重写的类上

干杯, 杰森


这似乎是一个设计问题

您有几个选择:

  • 获取A.DoThis()的大部分,并将其移动到另一个名为适当的方法(DoThat()?)的方法(protected?)。现在,你可以直接打电话给它
  • 拆分您的对象,并考虑使用构造函数而不是继承来重用行为。
    可能重复:我想你的意思是从C中的方法调用A.f()?我只是在猜测,但是你不能将
    这个
    转换为C吗?((C)本条);这似乎无法编译(无论如何,当我尝试它时)。你是否在考虑C++,它有类似的语法来调用继承链的方法?这不编译,也不工作,理论上,除非它们是静态的,否则不能调用这种方法,在这种情况下它们不能是虚拟的。对不起,我确实有C++的判断失误。用变通方法编辑。谢谢,这不是我自己的设计。在这种情况下,B类和C类是Telerik组件。类B提供了我所需要的大部分功能,但是为了实现一些功能,我需要在C中调用方法。
    
    Calling from MyClass
    Calling from MyBaseClass
    
        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();
        }
    }