C #: Любой способ пропустить один из базовых вызовов в полиморфизме? - PullRequest
9 голосов
/ 02 августа 2011
class GrandParent
{
    public virtual void Foo() { ... }
}

class Parent : GrandParent
{
    public override void Foo()
    {
       base.Foo();

       //Do additional work
    }
}

class Child : Parent
{
    public override void Foo()
    {
        //How to skip Parent.Foo and just get to the GrandParent.Foo base?

        //Do additional work
    }
}

Как показывает приведенный выше код, как я могу сделать так, чтобы Child.Foo () выполнял вызов GrandParent.Foo () вместо того, чтобы идти в Parent.Foo ()? base.Foo() сначала ведет меня в родительский класс.

Ответы [ 6 ]

11 голосов
/ 02 августа 2011

Ваш дизайн неправильный, если вам это нужно.
Вместо этого поместите логику для каждого класса в DoFoo и не вызывайте base.DoFoo, когда вам это не нужно.

class GrandParent
{
    public void Foo()
    {
        // base logic that should always run here:
        // ...

        this.DoFoo(); // call derived logic
    }

    protected virtual void DoFoo() { }
}

class Parent : GrandParent
{
    protected override void DoFoo()
    {    
       // Do additional work (no need to call base.DoFoo)
    }
}

class Child : Parent
{
    protected override void DoFoo()
    {  
        // Do additional work (no need to call base.DoFoo)
    }
}
6 голосов
/ 02 августа 2011

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

Переосмыслите свой дизайн.

3 голосов
/ 02 августа 2011

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

2 голосов
/ 02 августа 2011

Нет, это невозможно. Представьте себе, какими безумными были бы вещи, если бы это было возможно.

Если вы хотите, чтобы в случае Child было пропущено что-то конкретное, подумайте о том, чтобы переделать свой дизайн, чтобы лучше представить, что вам нужно (например, может быть, вам нужно переопределить что-то еще в классе Child). Или вы можете предоставить еще один Foo() в классе Parent, который ничего не делает, кроме как вызвать его base.Foo().

1 голос
/ 02 августа 2011

Если у вас есть контроль над кодом, самый простой способ - создать защищенный метод в родительском классе, который вызывает только base.Foo (), а реализация вашего дочернего класса Foo явно вызывает этот метод

0 голосов
/ 20 мая 2016

У нас был именно такой сценарий в большом проекте, где производные методы вызывались из разных мест. Из-за того, что сценарии управления изменениями и контроля качества не должны нарушаться, помимо прочих ограничений, «радикальный» рефакторинг и реструктуризация классов не всегда возможны в большом зрелом проекте. Также мы не хотели переопределять метод и исключать всю базовую функциональность. Большинство решений, встречающихся в других местах, выглядели немного неуклюже, но решение от Джош Джордан о том, как вызывать base.base , было весьма полезным.

Однако мы следовали подходу ниже (который, как я вижу, сейчас очень похож на предложенный Даном Абрамовым).

</p>

<pre><code>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.
    }
}   

...