Как позвонить base.base.method ()? - PullRequest
       16

Как позвонить base.base.method ()?

102 голосов
/ 24 февраля 2010
// 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();
    }
}

Результат:

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

Как мне переписать класс 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.");
    }
}

Ответы [ 12 ]

88 голосов
/ 24 февраля 2010

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

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

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

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

81 голосов
/ 14 сентября 2015

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

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();            
    }
}
23 голосов
/ 24 февраля 2010

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

10 голосов
/ 24 февраля 2010

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

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");
    }
}

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

6 голосов
/ 02 октября 2015

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

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());
    }
}
3 голосов
/ 11 февраля 2016
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(); 
    }
}
3 голосов
/ 06 мая 2011

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

2 голосов
/ 16 июня 2016

Мой 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 для облегчения работы.

1 голос
/ 16 июня 2013

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

Вот пример:

//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();  
     }         
}
0 голосов
/ 11 октября 2018

Похоже, что существует множество таких вопросов, связанных с наследованием метода-члена от класса Grandparent, переопределением его во втором классе, а затем повторным вызовом его метода из класса Grandchild. Почему бы просто не наследовать членов бабушки и дедушки от внуков?

class A
{
    private string mystring = "A";    
    public string Method1()
    {
        return mystring;
    }
}

class B : A
{
    // this inherits Method1() naturally
}

class C : B
{
    // this inherits Method1() naturally
}


string newstring = "";
A a = new A();
B b = new B();
C c = new C();
newstring = a.Method1();// returns "A"
newstring = b.Method1();// returns "A"
newstring = c.Method1();// returns "A"

Кажется простым .... внучка наследует здесь метод бабушки и дедушки. Подумайте об этом ..... вот как «Объект» и его члены, такие как ToString (), наследуются для всех классов в C #. Я думаю, что Microsoft не проделала хорошую работу по объяснению базового наследования. Слишком много внимания уделяется полиморфизму и реализации. Когда я копаюсь в их документации, нет примеров этой самой основной идеи. (

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...