機能の拡張 -デリゲート-

ホームC#プログラミング応用講義 > デリゲート

目次

確かに難しい

デリゲートという項目は非常に難しいといっていいでしょう。
手持ちの本で唯一デリゲートを説明しているものは「心配ありません」などと書いていましたが、これを難しくないといったら何が難しいのかという感じです。

私自身、説明することも使うこともできますが、実際のプログラムの中でそれを利用したことはありません。
ではなぜわざわざ難しい「デリゲート」というものを学ぶのかというと、「イベント」がその拡張範囲の中にあるからです。

イベントは皆さんも知っているでしょう。「Load」イベントや「TextChanged」イベント、「Click」イベントなどがそれに当たります。
これはもともとあるものを利用するだけ十分かと思いますが、せっかくなので応用講義で包括的に習得しようかと思います。

とすると、デリゲートは避けて通れません。非常に複雑な概念であり、こんなのありかと思うようなものですが、避けて通れないのですからやむを得ません。

ここでは2つのサンプルを通じてデリゲートを最低限習得します。
その知識を利用して、次回のイベントにつなげます。

このページの内容は難しいでしょう。まだ書いていませんが、そうなりそうな予感がします。
でも、誰でも難しいと思うことですから、気楽に読み進めていってください。私もできるだけ簡単に書きたいと思います。

サンプル1

デリゲートは一言で言えば、「メソッドをまるでオブジェクトのように使っちゃう」機能です。
オブジェクトはクラスから生成され、クラスの中にメンバとしてメソッドがあるという関係ですから、例外的処置だと思っていいでしょう。

で、メソッドをオブジェクトのように利用するわけですから、メソッドをクラスのようにしなければならないでしょう。
クラスではありません。クラスのように使っちゃおう。メソッドを。そういう例外的処置です。

始めに述べておきます。なぜメソッドをオブジェクトのように使うか。
それは「メソッド」よりも「オブジェクト」の方が力強いからです。オブジェクトは単体で完全に独立できますから、メソッドよりは頼もしそうですね。
単なるメソッドをオブジェクトとして使うことで、より広く利用できます。

で、話を元に戻し、クラスの宣言は「class」キーワードでしたが、メソッドをあたかもクラスのように利用し、後にオブジェクトを生成するメソッドの宣言は
delegate
です。これをメソッドの頭につけて、後は普通のメソッドのように、クラス定義の位置に定義します。(クラスの中でもできますが)

ここまで説明しましたから、早速サンプルを見てみましょう。
using System;

delegate string TRICK(string str);

class Test
{
    public static void Main(string[] args)
    {
        TRICK trick = new TRICK(TRICK1);
        string str = trick("深夜番組の出世頭");
        
        Console.WriteLine(str);
    }
    private static string TRICK1(string str)
    {
        return "TRICK1 は" + str + "です。";
    }
}
delegate が見えますね。これがあれば「あ、このメソッドはクラスのようになっていて、あとでオブジェクトのように動くんだな」と予想します。
言い忘れましたが、この変わったメソッドのことを「デリゲート」と呼びます。ただキーワードをカタカナに直しただけですが。

Main() の中を見てください。オブジェクトの生成キーワード「new」で、デリゲートをオブジェクト化しています。
面白いことに、コンストラクタの引数には「別の普通のメソッド TRICK1()」をとっています。

え、そんなのあったか? 下の方にありますから、確認します。
見れば見るほど普通のメソッドですが、デリゲートの特徴を確認できます。

シグニチャを確認してください。
・戻り値の型 string
・第1引数 string 型
これはデリゲートのシグニチャと一致しています。
コンストラクタに渡すメソッドは、デリゲートと同じシグニチャでなければなりません

目を Main() に戻して、
trick(...)
と呼び出しているところに注目します。

本当に変な動きをするでしょう。trick の中に収められたメソッドを呼び出す、そういうことを意味します。
ここでは入っているのが「TRICK1」ですから、それが呼び出されます。引数に文字列を渡して呼び出すんですね。

それ以降は普通です。戻ってきた str を表示しているだけです。

デリゲートはオブジェクトとなり、他のメソッドを中に放り込むことができます。
もちろん、
new TRICK(TRICK1)
としていますから、直接放り込んではいませんが、そう考えても差し支えはありません。

trick の中にポーンと放り込んじゃってます。これは意外と重要で、次の項目で学ぶマルチキャストにつながります。
なんと、trick は1個しか入らないわけではなく、たくさん入るんですね。

サンプル2

a += 1;
覚えていますか? この演算子 += や -=。複合代入演算子です。上のは以下のと同じ働きをします。
a = a + 1;
オブジェクトとなったデリゲートにはこの演算子を利用して多くのメソッドを放り込むことができます。
放り込んだメソッドは一括して配列のように扱われます。

using System;

delegate void TRICK();

class Test
{
    public static void Main(string[] args)
    {
        TRICK trick = new TRICK(TRICK1);
        trick += new TRICK(TRICK2);
        trick += new TRICK(TRICK3);
        
        trick();
    }
    private static void TRICK1()
    {
        Console.WriteLine("TRICK1 は深夜番組の出世頭です。");
    }
    private static void TRICK2()
    {
        Console.WriteLine("TRICK2 は深夜番組でも視聴率を取れることを証明しました。");
    }
    private static void TRICK3()
    {
        Console.WriteLine("TRICK3 は深夜番組からゴールデンへ昇格した大変珍しいドラマです。");
    }
}
ちなみに今度は戻り値の型が void です。

Main() の中ではいろいろ放り込んじゃってますね。TRICK1, TRICK2, TRICK3 がポーンと放り込まれてます。
で、trick() では一括して中にあるメソッドを呼び出します。

だから、このプログラムでは3行表示されます。
3つは放り込まれていますが、チェーンのように見事に配列化されていますから、順番に表示されます。決してごっちゃにはなりません。

配列のようになっているからには -= で削除していくこともできそうですが、その通りできます。
しかし、多くは += しか使われませんから、ここでは説明しません。配列なんかも複雑に絡みますしね。

さて、オブジェクト化することでメソッドよりも力強くなるといったのがお分かりになったでしょうか。
チェーンのようにメソッドをつないでいくこともできましたし、頼もしいですね。このためにデリゲートはあります。

始めに「難しい」と脅かした割には簡単に説明できたような気がします。
ここを読んで、デリゲートを身に着けてください。

またまた言うのを忘れましたが、上のようにチェーンのようにメソッドをつなげていることを「マルチキャスト」といいます。かっこいい名前だなあ、と思うのは私だけか? 「マルチ」のところとか。

注)
trick の中にメソッドを放り込むといいました。この中でも言いましたが、直接放り込んでいるわけではありません。
new TRICK() ですから、オブジェクトが入っており、マルチキャストではそれらがチェーンのようにつながっています。
しかし、イメージとしてはメソッドが入っていると考えても差し支えはない、ということです。

[ ステップアップC# ] [ C#プログラミング応用講義 ]