C#: Любой способ пропустить один из базовых вызовов в полиморфизме?

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 ответов

Решение

Ваш дизайн не так, если вам это нужно.
Вместо этого поместите логику для каждого класса в 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)
    }
}

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

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

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

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

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

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

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

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

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

Все эти твердые мнения...

Иногда имеет смысл использовать 99% чего-либо...

public class Base
{
  public virtual void Foo()
  {
   // Do something
  }
}

public class DerivedLevel1 : Base
{
  public override void Foo()
  {
    DerivedLevel1Foo();
  }
  protected void DerivedLevel1Foo()
  {
    // Do something
    base.Foo();
  }
}

public class DerivedLevel2 : DerivedLevel1
{
  public override void Foo()
  {
   DerivedLevel2Foo();
  }
  protected void DerviedLevel2Foo()
  {
    // Do something
    base.Foo();
  }
}

public class Special : Derived
{
  public override void Foo()
  {
    // Don't do DerivedLevel2Foo()
    base.DerivedLevel1Foo();
  }
}
Другие вопросы по тегам