デリゲート(delegate)は、直訳すると「委任」という意味です。これだけですと何のことだかわかりませんね。.NET Frameworkでは、メソッドを変数のように扱うことで、メソッドの実行を他の個所に委任する機能があります(図1)。これが「デリゲート」の正体です。

図1●イベント発生と処理を分離できる
図1●イベント発生と処理を分離できる

 C#のプログラムでは、何らかのイベント(メッセージ)が発生したときに、それに呼応するイベントを起こすことがあります。あるクラス内にデリゲートをたくさん保持しておき、イベントが発生した際にそれを実行するといったことが可能になります。デリゲート型で宣言した変数はオブジェクトなので、クラスの中から動的に取り外し可能です。しかも、イベント発生と、それに呼応する処理を分離できるためより柔軟なプログラミングが可能になります。

 デリゲートを難しいと思っている人は、まずその利用価値がどこにあり、なぜ必要なのか、といったことを理解すると、すんなりと頭に入ってくることでしょう。ここでは、デリゲートの利用例として、エラー処理の委譲と、非同期処理の例を見ていきます。

知らずに使っているデリゲート

 C#でプログラムを組む際に、イベントをよく利用すると思います。例えば、ボタンをクリックして、発生するイベントを処理する場合などです。このイベントの機能は、デリゲートが重責を担う機能の一つです。ボタンのクリックイベントを例に挙げます。

図2●この処理(メソッド)の指定をデリゲートが担っている
図2●この処理(メソッド)の指定をデリゲートが担っている
図3●デリゲートを使って例外処理をまとめる
図3●デリゲートを使って例外処理をまとめる

 ボタンをクリックすると、ボタン内部でクリックイベントが発生し、指定された処理が実行されます(図2)。クリックイベントが発生した際、どの処理(メソッド)を指定すればよいのかをデリゲートで決めているのです。

 このようにメソッドを指定できるという利点は、例外処理に応用できます。ここで、エラー処理をデリゲート化することを考えてみましょう。デリゲートを利用すれば、例外処理をまとめることができます。ボタンクリックイベントと同じような流れで、デリゲートを使ったサンプルプログラムを作成します。誌面の都合上、名前空間の指定などは省いて掲載しています。リスト1のSubクラスとリスト2のMainクラスを作成し、SubクラスにはAという処理(メソッド)を記述します。MainクラスのMain処理では、Subクラスのインスタンスを生成して処理Aを実行します。この処理Aの実行中に発生した例外エラーは、処理A内でキャッチしますが、キャッチした際のエラー処理は、Mainクラスにまとめて記述したい場合を考えます(図3)。

リスト1●Subクラス
リスト1●Subクラス
リスト2●Mainクラス
リスト2●Mainクラス

 (1)で、ExceptionHandlerという名前のデリゲートを引数にExceptionを持つ型として定義して、(2)でHandleExceptionという名前の変数で宣言しています。(3)でHandleExceptionを実行していますが、これはHandleExceptionに代入されたメソッドを実行していることを指します。

 リスト1では、SubAメソッドを実行すると、(4)の部分で必ず例外エラーが発生するようにしており、その影響によって本来ならばtrueを返却したい(5)のところが、コンパイルエラーになるためコメントアウトしています。