web-dev-qa-db-ja.com

基本メソッド呼び出しを強制する

JavaまたはC#に、継承クラスに基本実装を呼び出すように強制する構造がありますか?super()またはbase()を呼び出すことはできますが、コンパイル時エラーをスローさせることは可能ですか?呼び出されない場合は?それは非常に便利です。

-編集-

私は主にメソッドのオーバーライドに興味があります。

24
irwinb

それを行うことはありませんし、すべきではありません。

基本クラスでこれを持っているようなものであれば、私が手に負えないと考えることができる最も近いもの:

public virtual void BeforeFoo(){}

public void Foo()
{

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

}

public virtual void AfterFoo(){}

そして、継承するクラスがBeforeFooやAfterFooをオーバーライドできるようにします

18
MStodd

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

それは醜いですが、それはあなたが望むものを達成します。それ以外の場合は、スーパークラスメソッドを呼び出すように注意する必要があります。

技術的な解決策を使用するのではなく、設計をいじって問題を修正できるかもしれません。それは不可能かもしれませんが、おそらく考える価値があります。

編集:多分私は質問を誤解しました。一般的にコンストラクターまたはメソッドについてのみ話しているのですか?私は一般的な方法を想定しました。

9
Cameron Skinner

次の例では、メソッドをオーバーライドするときに基本機能が継承されていない場合、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() {
    }
}
4
Lea Hayes

あなたはこれを見たいかもしれません(スーパーアンチパターンを呼び出します) http://en.wikipedia.org/wiki/Call_super

4
Kemoda

基本クラスの動作がオーバーライドされないことを強制したいが、それを拡張できることを正しく理解している場合は、テンプレートメソッドデザインパターンを使用し、C#ではメソッド定義に仮想キーワードを含めません。

2
Sebastian Piu

いいえ、できません。事前または事後のアクションを実行する関数が必要な場合は、次のようにします。

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
   }
}
1
Russell McClure

ここですべての返信を読んだわけではありません。しかし、私は同じ質問を考えていました。私が本当にやりたいことを検討した後、基本メソッドの呼び出しを強制したいのであれば、そもそも基本メソッドを仮想(オーバーライド可能)と宣言すべきではなかったように思えました。

1
Chris Barker

私はこの投稿に出くわしましたが、必ずしも特定の答えが好きではなかったので、私は自分自身を提供すると思いました...

C#には、基本メソッドが呼び出されるように強制する方法はありません。したがって、フォローアップ開発者は基本メソッドを呼び出さなければならないことに気付かない可能性があるため、コーディング自体はアンチパターンと見なされます。そうしないと、クラスが不完全または不良状態になります。

ただし、このタイプの機能が必要であり、それに応じて実行できる状況を見つけました。通常、派生クラスには基本クラスのリソースが必要です。通常はプロパティを介して公開される可能性のあるリソースを取得するために、代わりにメソッドを介して公開されます。派生クラスは、メソッドを呼び出してリソースを取得する以外に選択肢がないため、基本クラスのメソッドが確実に実行されます。

次の論理的な質問は、代わりにコンストラクターに入れないのはなぜですか?その理由は、それが操作の順序の問題である可能性があるためです。クラスが構築された時点で、まだいくつかの入力が欠落している可能性があります。

これは質問から逃れることができますか?はいといいえ。はい、それは派生クラスに特定の基本クラスメソッドを呼び出すことを強制します。いいえ、overrideキーワードではこれを行いません。これは、おそらく、この投稿への回答を探している個人に役立つでしょうか。

私はこれを福音として説教しているのではありません。個人がこのアプローチの欠点を感じたら、それについて聞いてみたいと思います。

0
mschmit

実行可能なソリューションが組み込まれているとは思わないでください。ただし、それを実行できる別のコード分析ツールがあると確信しています。

0
Matti Virkkunen

[〜#〜] edit [〜#〜]コンストラクターとしての構成の誤読。問題の非常に限られたサブセットに適合するため、CWのままにしておきます。

C#では、基本型に少なくとも1つのパラメーターを持つ単一のコンストラクターを定義することで、この動作を強制できます。これにより、デフォルトのコンストラクターが削除され、派生型が指定されたベースを明示的に呼び出すように強制されます。そうしないと、コンパイルエラーが発生します。

class Parent {
  protected Parent(int id) {
  }
}

class Child : Parent { 
  // Does not compile
  public Child() {}
  // Also does not compile
  public Child(int id) { }
  // Compiles
  public Child() :base(42) {}

}
0
JaredPar

ベースコールを強制しないでください。本体でオーバーライド可能な(例:抽象)保護されたメソッドを呼び出しながら、親メソッドに必要な処理を実行させます。

0
Sentinel

Javaでは、コンパイラーはコンストラクターの場合にのみこれを強制できます。

コンストラクターは、継承チェーンのずっと上で呼び出す必要があります。つまり、DogがAnimal extends 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
    }
}
0
pstanton