base.SomeVirtualMethod
そのAPIのドキュメントで、そうする必要があると指定されている場合にのみ、を呼び出す必要があります。それ以外の場合は、オプションとして暗示する必要があります。基本メソッドを呼び出す必要があるが、明示的には述べていないAPIは、不適切に設計されています。
基本呼び出しが必要な理由は、設計が不十分であるためです。これは、メソッドをオーバーライドする誰かが何をするかを期待できず、必要なコードや重要なコードを実行するために基本メソッドを呼び出すかどうかを確信できないためです。
つまり、ドキュメントを参照してください。そうでない場合は、通常は必要ありません。.NET Frameworkはこのようなガイドラインに基づいて設計されており、ほとんどの仮想メソッドでは、これらの理由からベースを呼び出す必要はありません。そうするものは文書化されています。
基本仮想メソッドを呼び出す非常に重要な理由を指摘してくれたrokenに感謝します。それは、イベントを使用するときです。ただし、これが常に当てはまるとは限らないという私の反論は、特に.NETのイディオムとパターンに従わないサードパーティのライブラリまたはクラスを使用している場合は、確実性がありません。この例を見てください。
namespace ConsoleApplication12
{
using System;
using System.Diagnostics;
class Foo
{
public Foo() {
}
public event EventHandler Load;
protected virtual void OnLoad() {
EventHandler handler = Load;
if (handler != null) {
handler(this, new EventArgs());
}
Debug.WriteLine("Invoked Foo.OnLoad");
}
public void Run() {
OnLoad();
}
}
class DerivedFoo : Foo
{
protected override void OnLoad() {
base.OnLoad();
Debug.WriteLine("Invoked DerivedFoo.OnLoad");
}
}
class Program
{
static void Main(string[] args) {
DerivedFoo dFoo = new DerivedFoo();
dFoo.Load += (sender, e) => {
Debug.WriteLine("Invoked dFoo.Load subscription");
};
dFoo.Run();
}
}
}
この例を実行すると、、、およびイベントサブスクリプションへの3つの呼び出しが得Foo.OnLoad
られDerivedFoo.OnLoad
ますdFoo.Load
。の呼び出しをコメントアウトすると、へのbase.OnLoad
呼び出しDerivedFoo
は1回だけにDerivedFoo.OnLoad
なり、ベースとサブスクライバーは呼び出されませんでした。
その要点は、ドキュメンテーション次第であるということは依然として強いです。基本仮想メソッドの実装がサブスクライバーを呼び出すかどうかはまだわかりません。ですから、それは明らかなはずです。幸いなことに、.NET Frameworkは、フレームワーク設計者のおかげで.NETイベントモデルと非常に一貫性がありますが、APIのドキュメントを常に読むのに十分なストレスを感じることはできません。
これは、イベントをまったく処理していないときに多くの効果を発揮しますが、抽象基本クラスのようなものです。抽象クラスの基本イベントを呼び出すかどうかをどうやって知るのですか?抽象クラスはデフォルトの実装を提供しますか、それともあなたがそれを提供することを期待していますか?
ドキュメントは、仮想メンバーの契約を定義するための最も強力で明確な方法です。これが、.NET Frameworkデザイナーチームが、出荷される抽象クラスに少なくとも1つの具体的な実装を提供する理由の1つです。
Krzysztof Cwalinaは、フレームワークの設計ガイドラインでそれを最もよく言っていると思います。
私がよく受ける質問は、仮想メンバーのドキュメントに、オーバーライドで基本実装を呼び出す必要があると記載する必要があるかどうかです。答えは、オーバーライドは基本クラスのコントラクトを保持する必要があるということです。基本実装を呼び出すか、他の方法でそれを行うことができます。メンバーが(オーバーライドで)そのコントラクトを保持する唯一の方法がそれを呼び出すことであると主張できることはまれです。多くの場合、ベースを呼び出すことが契約を維持するための最も簡単な方法かもしれません(そしてドキュメントはそれを指摘する必要があります)が、それが絶対に必要になることはめったにありません。
そして、私は完全に同意します。基本実装をオーバーライドして呼び出さないことにした場合は、同じ機能を提供する必要があります。
これにより、コメントでの混乱が解消されることを願っています。