.NET Tips/Delegate
デリゲートは、実行時にメソッドを参照する型です。関数ポインタのように使用することができます。
デリゲートは同期処理です。つまり、デリゲートを呼び出すと、その処理が終了するまで次の処理に進めません。以下のサンプルでそのことを確認できます。
このサンプルをコンパイルして実行すると、次の結果が得られます。
もしデリゲートが非同期処理なら、 "foo start." から "foo end." の間で 3 秒間停止している間に "event called." が呼ばれるはずです (場合によるけれど) 。
マルチキャスト デリゲートも同期処理です。マルチキャスト デリゲートの場合、デリゲート変数に追加した順番にメソッドが呼ばれます。以下のサンプルでそのことを確認できます。
このサンプルをコンパイルして実行すると、次の結果が得られます。
デリゲートとして呼び出したメソッドの処理で例外がスローされると、呼び出し元に例外がスローされます (まぁ、当たり前ですが) 。以下のサンプルでそのことを確認できます。
このサンプルをコンパイルして実行すると、次の結果が得られます。
Foo メソッドをデリゲート変数に登録し、デリゲートとして呼び出します。 Foo メソッドは InvalidOperationException 例外をスローします。 InvalidOperationException 例外は Main メソッドでキャッチされ、コンソールに文字列表現が出力されます。その後、 "event called." がコンソールに表示されます。このことにより、デリゲート呼び出しでスローされた例外は、呼び出し元にスローされ、キャッチすることもできるといえます。
マルチキャスト デリゲートとして呼び出したメソッドの中で例外がスローされると、そのデリゲート呼び出しはそこで終了します。例えば、 Foo, Bar, Boo メソッドをマルチキャスト デリゲートとして呼び出して Bar メソッドが例外をスローした場合、 Boo メソッドは呼び出されません。以下のサンプルでそのことを確認できます。
Bar メソッドの呼び出しで InvalidOperationException 例外がスローされますが、その後の Boo メソッドが呼び出されず、 "event called." が表示されていることが分かります。
デリゲートは同期処理
デリゲートは同期処理です。つまり、デリゲートを呼び出すと、その処理が終了するまで次の処理に進めません。以下のサンプルでそのことを確認できます。
class SampleDelegate1 { public static void Main() { EventHandler e = new EventHandler(Foo); Console.WriteLine("event calling."); e(null, null); Console.WriteLine("event called."); } public static void Foo(object sender, EventArgs e) { Console.WriteLine("foo start."); Thread.Sleep(3000); Console.WriteLine("foo end."); } }
このサンプルをコンパイルして実行すると、次の結果が得られます。
event calling. foo start. foo end. event called.
もしデリゲートが非同期処理なら、 "foo start." から "foo end." の間で 3 秒間停止している間に "event called." が呼ばれるはずです (場合によるけれど) 。
マルチキャスト デリゲートも同期処理です。マルチキャスト デリゲートの場合、デリゲート変数に追加した順番にメソッドが呼ばれます。以下のサンプルでそのことを確認できます。
class SampleDelegate2 { public static void Main() { EventHandler e = new EventHandler(Foo); e += new EventHandler(Bar); e += new EventHandler(Boo); Console.WriteLine("event calling."); e(null, null); Console.WriteLine("event called."); } public static void Foo(object sender, EventArgs e) { Console.WriteLine("foo start."); Thread.Sleep(1000); Console.WriteLine("foo end."); } public static void Bar(object sender, EventArgs e) { Console.WriteLine("bar start."); Thread.Sleep(1000); Console.WriteLine("bar end."); } public static void Boo(object sender, EventArgs e) { Console.WriteLine("boo start."); Thread.Sleep(1000); Console.WriteLine("boo end."); } }
このサンプルをコンパイルして実行すると、次の結果が得られます。
event calling. foo start. foo end. bar start. bar end. boo start. boo end. event called.
デリゲートの例外処理
デリゲートとして呼び出したメソッドの処理で例外がスローされると、呼び出し元に例外がスローされます (まぁ、当たり前ですが) 。以下のサンプルでそのことを確認できます。
class SampleDelegate3 { public static void Main() { EventHandler e = new EventHandler(Foo); Console.WriteLine("event calling."); try { e(null, null); } catch (InvalidOperationException ex) { Console.WriteLine(ex); } Console.WriteLine("event called."); } public static void Foo(object sender, EventArgs e) { Console.WriteLine("foo start."); Thread.Sleep(1000); throw new InvalidOperationException(); } }
このサンプルをコンパイルして実行すると、次の結果が得られます。
event calling. foo start. System.InvalidOperationException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 at SampleDelegate3.Foo(Object sender, EventArgs e) at SampleDelegate3.Main() event called.
Foo メソッドをデリゲート変数に登録し、デリゲートとして呼び出します。 Foo メソッドは InvalidOperationException 例外をスローします。 InvalidOperationException 例外は Main メソッドでキャッチされ、コンソールに文字列表現が出力されます。その後、 "event called." がコンソールに表示されます。このことにより、デリゲート呼び出しでスローされた例外は、呼び出し元にスローされ、キャッチすることもできるといえます。
マルチキャスト デリゲートとして呼び出したメソッドの中で例外がスローされると、そのデリゲート呼び出しはそこで終了します。例えば、 Foo, Bar, Boo メソッドをマルチキャスト デリゲートとして呼び出して Bar メソッドが例外をスローした場合、 Boo メソッドは呼び出されません。以下のサンプルでそのことを確認できます。
event calling. foo start. foo end. bar start. System.InvalidOperationException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 at SampleDelegate4.Bar(Object sender, EventArgs e) at System.EventHandler.Invoke(Object sender, EventArgs e) at SampleDelegate4.Main() event called.
Bar メソッドの呼び出しで InvalidOperationException 例外がスローされますが、その後の Boo メソッドが呼び出されず、 "event called." が表示されていることが分かります。
2005年12月25日(日) 20:36:22 Modified by uguuxp