Formの派生クラスでLoadイベントを使わずにOnLoadイベントをOverrideするのは何故ですか?
なんて事を最近会社に派遣されてきたC#初心者に聞かれたので、その理由をここに書いてみる。
聞かれた事は、
class MyForm : System.Windows.Forms.Form { private void MyForm_Load(object sender, EventArgs e) { // DoSomething } }
ではなくて
class MyForm : System.Windows.Forms.Form { protected override void OnLoad(EventArgs e) { base.OnLoad(e); // DoSomething } }
するのは何故か?という事。
これにはいくつかの理由があって、
- .NETのクラスライブラリのガイドラインにそうしろと書いてある。
- イベントは基本的に外部に知らせるためのものであり、内部で使うものではない。
- OnLoadメソッドがLoadイベントに登録されたイベントハンドラを呼び出している。(理由になってないけど)
1番の理由が最も大きいかな。.NETのクラスライブラリのデザインガイドラインで決められているため、それに従って作っていると他人が書いたソースでも理解しやすくなる。
2番はコンポーネントという観点で見れば至極当たり前。
3番でいいたい事は、Formの実際のソースを想像してみると
class Form : System.Windows.Forms.ContainerControl { // イベント public event EventHandler Load; protected virtual void OnLoad(EventArgs e) { // イベントハンドラが登録されているかチェック if(Load != null) Load(this, e); } protected override void WndProc(ref Message m) { // なんかウィンドウプロシージャをオーバーライドして // フォームがロードされたようなメッセージが飛んできたら OnLoad(EventArgs.Empty); } }
てな事になっているはず。実際自分でイベントを実装する時も上記のようなデザインで行うのが基本。
何故こんなデザインになっているかというと、イベントを発生させるには「Load(引数)」のように呼び出すが、派生クラスでは(言語仕様上)この操作ができなくなっている。そのため派生クラスで自由にイベントを呼び出せる用にOn〜メソッドという名前のヘルパーメソッドが用意されているのだ。
そしてこのヘルパーメソッドをOverrideする事によって、イベントハンドラの前後に独自の処理を入れたり、そもそもイベントを呼び出さなかったりなんて事ができる。
class MyForm : System.Windows.Forms.Form { protected override void OnLoad(EventArgs e) { // イベントの前になんか処理する。 // この呼び出しでLoadイベントが呼び出される base.OnLoad(e); // イベントの後でなんか処理する。 } }
こんな感じだと自分は理解している。