Как вызвать base.base.method()?

// Cannot change source code
class Base
{
    public virtual void Say()
    {
        Console.WriteLine("Called from Base.");
    }
}

// Cannot change source code
class Derived : Base
{
    public override void Say()
    {
        Console.WriteLine("Called from Derived.");
        base.Say();
    }
}

class SpecialDerived : Derived
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
}

class Program
{
    static void Main(string[] args)
    {
        SpecialDerived sd = new SpecialDerived();
        sd.Say();
    }
}

Результат:

Вызывается со специальной производной.
Вызывается из Derived./* это не ожидается */
Вызывается из базы.

Как я могу переписать класс SpecialDerived, чтобы не вызывать метод "Derived" среднего класса?

UPDATE: Причина, по которой я хочу наследовать от Derived вместо Base, - это класс Derived содержит много других реализаций. Поскольку я не могу сделать base.base.method() здесь, я думаю, лучший способ - сделать следующее?

//Невозможно изменить исходный код

class Derived : Base
{
    public override void Say()
    {
        CustomSay();

        base.Say();
    }

    protected virtual void CustomSay()
    {
        Console.WriteLine("Called from Derived.");
    }
}

class SpecialDerived : Derived
{
    /*
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
    */

    protected override void CustomSay()
    {
        Console.WriteLine("Called from Special Derived.");
    }
}

Ответ 1

Это плохая практика программирования и не разрешена в С#. Это плохая практика программирования, потому что

  • Детали grandbase - это детали реализации базы; вы не должны полагаться на них. Базовый класс обеспечивает абстракцию над вершиной бабушки; вы должны использовать эту абстракцию, а не создавать обход, чтобы избежать этого.

  • Вы получили свою базу, потому что вам нравится то, что она делает, и хотите ее повторно использовать и расширять. Если вам не нравится то, что он делает, и вы хотите обойти его, а не работать с ним, то почему вы проиграли его в первую очередь? Выводите из grandbase самостоятельно, если это функциональность, которую вы хотите использовать и расширяете.

  • Базе могут потребоваться определенные инварианты для целей безопасности или семантической согласованности, которые поддерживаются деталями того, как база использует методы grandbase. Предоставление производному классу базы пропустить код, который поддерживает эти инварианты, может привести базу к непоследовательному, поврежденному состоянию.

Ответ 2

Просто хочу добавить это здесь, так как люди до сих пор возвращаются к этому вопросу даже спустя много времени. Конечно, это плохая практика, но все же возможно (в принципе) делать то, что хочет автор:

class SpecialDerived : Derived
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        var ptr = typeof(Base).GetMethod("Say").MethodHandle.GetFunctionPointer();            
        var baseSay = (Action)Activator.CreateInstance(typeof(Action), this, ptr);
        baseSay();            
    }
}

Ответ 3

Вы не можете использовать С#. От IL это фактически поддерживается. Вы можете сделать вызов non-virt для любого из ваших родительских классов... но, пожалуйста, не делайте этого.:)

Ответ 4

Ответ (который я знаю не то, что вы ищете):

class SpecialDerived : Base
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
}

По правде говоря, у вас есть только непосредственное взаимодействие с классом, который вы наследуете. Подумайте об этом классе как о слое - предоставляя столько же или как мало его, либо его родительскую функциональность, как она хочет к своим производным классам.

EDIT:

Ваше редактирование работает, но я думаю, что я бы использовал что-то вроде этого:

class Derived : Base
{
    protected bool _useBaseSay = false;

    public override void Say()
    {
        if(this._useBaseSay)
            base.Say();
        else
            Console.WriteLine("Called from Derived");
    }
}

Конечно, в реальной реализации вы можете сделать что-то более похожее на расширяемость и удобство обслуживания:

class Derived : Base
{
    protected enum Mode
    {
        Standard,
        BaseFunctionality,
        Verbose
        //etc
    }

    protected Mode Mode
    {
        get; set;
    }

    public override void Say()
    {
        if(this.Mode == Mode.BaseFunctionality)
            base.Say();
        else
            Console.WriteLine("Called from Derived");
    }
}

Затем производные классы могут соответствующим образом контролировать состояние своих родителей.

Ответ 5

Почему бы просто не привести класс child к определенному родительскому классу и вызвать конкретную реализацию? Это особая ситуация, и нужно использовать специальное решение. Однако вам придется использовать ключевое слово new в методах children.

public class SuperBase
{
    public string Speak() { return "Blah in SuperBase"; }
}

public class Base : SuperBase
{
    public new string Speak() { return "Blah in Base"; }
}

public class Child : Base
{
    public new string Speak() { return "Blah in Child"; }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Child childObj = new Child();

        Console.WriteLine(childObj.Speak());

        // casting the child to parent first and then calling Speak()
        Console.WriteLine((childObj as Base).Speak()); 

        Console.WriteLine((childObj as SuperBase).Speak());
    }
}

Ответ 6

Вы также можете сделать простую функцию в производном классе первого уровня, чтобы вызвать функцию grand base

Ответ 7

My 2c для этого - реализовать функциональные возможности, которые вы требуете, вызывать в классе инструментальных средств и вызывать их там, где вам нужно:

// Util.cs
static class Util 
{
    static void DoSomething( FooBase foo ) {}
}

// FooBase.cs
class FooBase
{
    virtual void Do() { Util.DoSomething( this ); }
}


// FooDerived.cs
class FooDerived : FooBase
{
    override void Do() { ... }
}

// FooDerived2.cs
class FooDerived2 : FooDerived
{
    override void Do() { Util.DoSomething( this ); }
}

Это требует некоторой мысли о привилегии доступа, возможно, вам придется добавить некоторые методы доступа internal для облегчения функциональности.

Ответ 8

В случаях, когда у вас нет доступа к источнику производного класса, но вам нужен весь источник производного класса помимо текущего метода, тогда я бы рекомендовал вам также сделать производный класс и вызвать реализацию производного класса.

Вот пример:

//No access to the source of the following classes
public class Base
{
     public virtual void method1(){ Console.WriteLine("In Base");}
}
public class Derived : Base
{
     public override void method1(){ Console.WriteLine("In Derived");}
     public void method2(){ Console.WriteLine("Some important method in Derived");}
}

//Here should go your classes
//First do your own derived class
public class MyDerived : Base
{         
}

//Then derive from the derived class 
//and call the bass class implementation via your derived class
public class specialDerived : Derived
{
     public override void method1()
     { 
          MyDerived md = new MyDerived();
          //This is actually the base.base class implementation
          MyDerived.method1();  
     }         
}

Ответ 9

public class A
{
    public int i = 0;
    internal virtual void test()
    {
        Console.WriteLine("A test");
    }
}

public class B : A
{
    public new int i = 1;
    public new void test()
    {
        Console.WriteLine("B test");
    }
}

public class C : B
{
    public new int i = 2;
    public new void test()
    {
        Console.WriteLine("C test - ");
        (this as A).test(); 
    }
}

Ответ 10

Как можно видеть из предыдущих сообщений, можно утверждать, что, если функциональность класса нужно обойти, то что-то не так в архитектуре класса. Это может быть правдой, но не всегда можно реструктурировать или реорганизовать структуру класса в большом зрелом проекте. Различные уровни управления изменениями могут быть одной проблемой, но чтобы сохранить существующую функциональность, действующую одинаково, после того, как рефакторинг не всегда является тривиальной задачей, особенно если применяются временные ограничения. В зрелом проекте это может быть обязательным для проведения различных регрессионных тестов после реорганизации кода; часто появляются неясные "странности", которые появляются. У нас была аналогичная проблема, в некоторых случаях унаследованная функциональность не должна выполняться (или должна выполнять что-то еще). Подход, который мы приводили ниже, заключался в том, чтобы поместить базовый код, который должен быть исключен в отдельной виртуальной функции. Затем эту функцию можно переопределить в производном классе и исключить или изменить функциональность. В этом примере "Текст 2" можно исключить из производного класса.

public class Base
{
    public virtual void Foo()
    {
        Console.WriteLine("Hello from Base");
    }
}

public class Derived : Base
{
    public override void Foo()
    {
        base.Foo();
        Console.WriteLine("Text 1");
        WriteText2Func();
        Console.WriteLine("Text 3");
    }

    protected virtual void WriteText2Func()
    {  
        Console.WriteLine("Text 2");  
    }
}

public class Special : Derived
{
    public override void WriteText2Func()
    {
        //WriteText2Func will write nothing when 
        //method Foo is called from class Special.
        //Also it can be modified to do something else.
    }
}

Ответ 11

Если вы хотите получить доступ к данным базового класса, вы должны использовать ключевое слово "this" или использовать это ключевое слово как ссылку для класса.

namespace thiskeyword
{
    class Program
    {
        static void Main(string[] args)
        {
            I i = new I();
            int res = i.m1();
            Console.WriteLine(res);
            Console.ReadLine();
        }
    }

    public class E
    {
        new public int x = 3;
    }

    public class F:E
    {
        new public int x = 5;
    }

    public class G:F
    {
        new public int x = 50;
    }

    public class H:G
    {
        new public int x = 20;
    }

    public class I:H
    {
        new public int x = 30;

        public int m1()
        {
           // (this as <classname >) will use for accessing data to base class

            int z = (this as I).x + base.x + (this as G).x + (this as F).x + (this as E).x; // base.x refer to H
            return z;
        }
    }
}