[Effective C#] 項目35 イベントハンドらよりもオーバーライドを優先すること

本当に日が空きました。一月から新しいお仕事です。難易度がむっちゃ高いので復習の意味も込めて Effective C# の紹介再開です。

本日の Effective C# は「項目35 イベントハンドらよりもオーバーライドを優先すること」です。

たとえば、Form が開かれた時の処理を、Form.Load イベントに登録するか、または Form.OnLoad() メソッドをオーバーライドするかの二種類の手段があります。

デザイナで作業しているとついついイベントで処理していますが、これはけた方がいいというお話です。理由として以下のものがあげられています。

  • イベントハンドラはオーバーライドよりも重たい処理である。
  • メソッドがイベントハンドラかどうかわかりにくい。
  • イベントハンドラは呼び出される保証がない。
    • ちなみに、三番目のメソッドがイベントハンドラかどうかわかりにくいというのは、イベントハンドラの登録するコードとイベントハンドラが別々の個所になる C# 特有の問題です。もちろん、VB.NET も AddHandler ステートメントを使えば同様の問題が起きるのですが、Handles キーワード を使えばその問題はありません。Handles は数少ない VB.NET が C# に勝っている部分だと思います。

      イベントハンドラは呼び出される保証がないってのは登録しているのになぜ? というのがあるんですが、以下のコードを見てください。

      internal class Program
      {
          public EventHandler<EventArgs> Load;
       
          private static void Main(string[] args)
          {
              var program = new Program();
              program.Load += Load1;
              program.Load += Load2;
              try
              {
                  program.OnLoad();
              }
              catch (Exception ex)
              {
                  Debug.WriteLine(ex);
              }
          }
       
          public virtual void OnLoad()
          {
              EventHandler<EventArgs> h = Load;
              if (h != null)
              {
                  h(this, new EventArgs());
              }
          }
       
          private static void Load1(object sender, EventArgs e)
          {
              Debug.WriteLine("Run Load1().");
              throw new InvalidOperationException();
          }
       
          private static void Load2(object sender, EventArgs e)
          {
              Debug.WriteLine("Run Load2().");
          }
      }

      Load1() メソッドで例外がおきたせいで、Load2() は実行されません。例外起きたから当たり前じゃないか! と思うかもしれませんが、必ず実行してほしい処理というのがあった場合は非常に困ります。

      また、イベントハンドラはこのように複数登録できますが、この処理は必ず最初に実行したいとか、逆に後始末なので必ず最後に実行したいとか、そういうのができません。オーバーライドならば、スーパークラスのメンバを先に呼び出すか後で呼び出すかコントロールできます。

      とはいえ、書籍にも書いてありますが、イベントハンドラを絶対に使うなというわけではありません。外部クラスはイベントハンドラを利用せざるをありませんし。

      経験上、イベントハンドラの多用は確かに痛い目見ます。イベントハンドラを実行順序に影響しやすいように書いた場合、下手に登録すると予想外の動きをします。本当はそういったものをイベントで実行してはいけないんですが、若気の至りでつい…。

コメントを追加

Filtered HTML

  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 使用できるHTMLタグ: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote> <img>
  • 次のタグを使用してソースコード構文をハイライトすることができます。: <code>, <blockcode>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>, <ruby> The supported tag styles are: <foo>, [foo].
  • 行と段落は自動的に折り返されます。

Plain text

  • HTMLタグは利用できません。
  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 行と段落は自動的に折り返されます。
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
イメージ CAPTCHA
Enter the characters shown in the image.
エラー | まさくらのブログ

エラー

サイトに予期せぬエラーが起こりました。しばらくたってから再度お試しください。