Вызов метода базового метода - PullRequest
21 голосов
/ 21 октября 2010

Есть ли в Java или C # конструкция, которая заставляет наследуемые классы вызывать базовую реализацию?Вы можете вызвать super () или base (), но возможно ли, чтобы он вызывал ошибку времени компиляции, если он не вызывается?Это было бы очень удобно ..

- edit -

Мне в основном любопытно переопределить методы.

Ответы [ 12 ]

15 голосов
/ 21 октября 2010

Нет и не должно быть ничего, чтобы сделать это.

Самая близкая вещь, о которой я могу подумать, если что-то вроде этого в базовом классе:

public virtual void BeforeFoo(){}

public void Foo()
{

this.BeforeFoo();
//do some stuff
this.AfterFoo();

}

public virtual void AfterFoo(){}

И разрешить наследующий класс переопределить BeforeFoo и / или AfterFoo

7 голосов
/ 21 октября 2010

Не на Java.Это может быть возможно в C #, но кто-то еще должен будет говорить с этим.

Если я правильно понимаю, вы хотите это:

class A {
    public void foo() {
        // Do superclass stuff
    }
}

class B extends A {
    public void foo() {
        super.foo();
        // Do subclass stuff
    }
}

Что вы можете сделать в Java, чтобы навязать использованиесуперкласс foo - это что-то вроде:

class A {
    public final void foo() {
        // Do stuff
        ...
        // Then delegate to subclass
        fooImpl();
    }

    protected abstract void fooImpl();
}

class B extends A {
    protected void fooImpl() {
        // Do subclass stuff
    }
}

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

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

РЕДАКТИРОВАТЬ: Может быть, я неправильно понял вопрос.Вы говорите только о конструкторах или методах вообще?Я предполагал методы в целом.

4 голосов
/ 04 октября 2011

Возможно, вы захотите посмотреть на это (позвоните в super antipatern) http://en.wikipedia.org/wiki/Call_super

2 голосов
/ 01 мая 2014

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

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

т.е. где Foo() не предназначен для непосредственного вызова:

public abstract class ExampleBase {
    private bool _baseInvoked;

    internal protected virtual void Foo() {
        _baseInvoked = true;
        // IMPORTANT: This must always be executed!
    }

    internal void InvokeFoo() {
        Foo();
        if (!_baseInvoked)
            throw new InvalidOperationException("Custom classes must invoke `base.Foo()` when method is overridden.");
    }
}

Работает:

public class ExampleA : ExampleBase {
    protected override void Foo() {
        base.Foo();
    }
}

Кричит:

public class ExampleB : ExampleBase {
    protected override void Foo() {
    }
}
2 голосов
/ 21 октября 2010

Если я правильно понимаю, что вы хотите добиться того, чтобы поведение вашего базового класса не переопределялось, но все же можно было его расширять, тогда я бы использовал шаблон проектирования метода шаблона, а в C # не включал ключевое слово virtual вопределение метода.

1 голос
/ 01 января 2014

Я не читал ВСЕ ответы здесь; Тем не менее, я рассматривал тот же вопрос. После просмотра того, что я ДЕЙСТВИТЕЛЬНО хотел сделать, мне показалось, что если я хочу ЗАВЕРШИТЬ вызов базового метода, мне не следовало бы вначале объявить базовый метод виртуальным (переопределенным).

1 голос
/ 21 октября 2010

Нет. Это невозможно. Если вам нужна функция, выполняющая некоторые действия до или после, сделайте что-то вроде этого:

internal class Class1
{
   internal virtual void SomeFunc()
   {
      // no guarantee this code will run
   }


   internal void MakeSureICanDoSomething()
   {
      // do pre stuff I have to do

      ThisCodeMayNotRun();

      // do post stuff I have to do
   }

   internal virtual void ThisCodeMayNotRun()
   {
      // this code may or may not run depending on 
      // the derived class
   }
}
0 голосов
/ 22 мая 2018

Не вызывайте базовый вызов. Сделайте так, чтобы родительский метод делал то, что вы хотите, при этом вызывая перезаписываемый (например, абстрактный) защищенный метод в своем теле.

0 голосов
/ 26 июля 2013

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

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

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

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

Отходит ли это от вопроса? И да и нет. Да, это заставляет производный класс вызывать определенный метод базового класса. Нет, это не происходит с ключевым словом override. Может ли это быть полезным для человека, который ищет ответ на этот пост, может быть.

Я не проповедую это как Евангелие, и если люди увидят обратную сторону этого подхода, я хотел бы услышать об этом.

0 голосов
/ 21 октября 2010

В Java компилятор может применять это только в случае Конструкторов.

Конструктор должен вызываться по всей цепочке наследования. Т.е. если Dog расширяет Animal расширяет Thing, конструктор для Dog должен вызывать конструктор для Animal должен вызывать конструктор для Thing.

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

Единственный способ обеспечить выполнение некоторого базового кода реализации - разделить перезаписываемый код на отдельный вызов метода:

public class Super
{
    public final void doIt()
    {
    // cannot be overridden
        doItSub();
    }

    protected void doItSub()
    {
     // override this
    }
}

public class Sub extends Super
{
    protected void doItSub()
    {
     // override logic
    }
}
...