web-dev-qa-db-ja.com

基本クラスメソッドを「適切に」オーバーライドする方法

このメソッドの実装以外に、基本クラスのメソッドをオーバーライドするたびに、3つの選択肢があるようです。

1)base.Method()を呼び出してから、実装を提供します。

2)実装を提供してから、base.Method()を呼び出します

3)実装を提供してください。

最近、ライブラリを使用しているときに、ライブラリが期待する方法を実装していないために導入されたバグがほとんどないことに気付きました。それが図書館の一部に悪いのか、それとも私の理解に何か問題があるのか​​はわかりません。

一例を挙げましょう。

public class ViewManager {
     public virtual void Customize(){
        PrepareBaseView();
     }
}

public class PostViewManager {
     public override void Customize(){
        base.Customize();
        PreparePostView();
     }
}


public class PreViewManager {
     public override void Customize(){
        PreparePreView();
        base.Customize();
     }
}


public class CustomViewManager {
     public override void Customize(){
        PrepareCustomView();
     }
}

ここでの私の質問は、親クラスがどの順序(またはオプション)を期待しているのかを、子クラスが(基本クラスの実装を見ることなく)どうやって知ることができるかということです。親クラスがすべての派生クラスの3つの代替の1つを強制できる方法はありますか?

35

子クラスは、どのように順序(またはオプション)が親クラスに期待されているかを(基本クラスの実装を見ることなく)どうやって知ることができますか?

メソッドをサブクラス化してオーバーライドするとき、これを「知る」方法はありません。ここでは、適切なドキュメントが本当に唯一のオプションです。

親クラスがすべての派生クラスの3つの代替の1つを強制できる方法はありますか?

ここでの唯一のオプションは、問題を回避することです。サブクラスがメソッドをオーバーライドできるようにする代わりに、非仮想として宣言し、適切な場所で仮想メソッドを呼び出すことができます。たとえば、サブクラスが「最初にバージョンを呼び出す」ことを強制する場合、次のようにします。

public class BaseClass {
    public void Method() // Non-virtual
    {
          // Do required work

          // Call virtual method now...
          this.OnMethod();
    }

    protected virtual void OnMethod()
    { // Do nothing
    }
 }

サブクラスはOnMethodを「オーバーライド」し、「メソッド」の作業後に発生する機能を提供できます。

これが必要な理由は、サブクラスが親クラスの実装を完全に置き換えることができるように仮想メソッドが設計されているためです。これは意図的に行われます。これを防ぎたい場合は、メソッドを非仮想化することをお勧めします。

39
Reed Copsey

これが、仮想メソッドをライブラリで出荷すると危険だと感じる理由です。真実は、基本クラスを見ずに実際に知ることは決してないということです。時には、reflektorを起動したり、ドキュメントを読んだり、試行錯誤してアプローチする必要があります。

自分でコードを書くとき、私はいつも次のようなルールに従うことに疲れていました。

保護された仮想メソッドをオーバーライドする派生クラスは、基本クラスの実装を呼び出す必要はありません。基本クラスは、その実装が呼び出されなくても、引き続き正常に動作する必要があります。

これは http://msdn.Microsoft.com/en-us/library/ms229011.aspx から取られていますが、これはイベントデザイン用です。ただし、Framework Design Guidelinesブックでこれを読んでいると思います( http://www.Amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756 )。

ただし、これは明らかに当てはまりません。たとえば、ASP.NET WebフォームではPage_Loadの基本呼び出しが必要です。

そのため、長いことも短いことも異なりますが、残念ながらすぐに知る方法はありません。疑問がある場合は、最初に呼び出しを省略します。

2
nullable

短い答えはノーです。子がベースメソッドを呼び出す順序を強制することはできません。

技術的には、この情報はベースオブジェクトのドキュメントに含める必要があります。子クラスのコードの前または後に何らかのコードを実行する必要がある場合は、次を実行できます。

1)基本クラスで非仮想関数を作成します。 MyFunctionと呼びましょう

2)基本クラスで保護された仮想関数を作成します。 _MyFunctionと呼びましょう

3)派生クラスに_MyFunctionメソッドを拡張させる。

4)MyFunctionに_MyFunctionを呼び出させ、呼び出す前または後に実行する必要があるコードを実行します。

この方法は見苦しく、多くの余分なコードが必要になるため、ドキュメントに通知を入れることをお勧めします。

1

基本クラスの要件は、ライブラリ設計者が文書化する必要があります。この問題は、いくつかのライブラリが主に封印されたクラスを含む理由です。

0
Frank