【C#】デリゲート(delegate)の使い方

スポンサーリンク

避けてきたこの単語「Delegate」に挑戦したいと思います。
出来るだけ分かりやすく、サンプルを作って説明していきます。
ただ小難しい説明は省くので正確に調べたい方は、別のサイトを確認してください。

Delegateって何?

一言で表現するなら、『関数(メソッド)を変数として定義する』って言う事です。
メリットを上げろと言われると正直難しいです。。。
ただ1つのソフトで1つの処理をキレイに見せるかにという観点では、必要な書き方だと思います。

使い方

定義の仕方

冒頭でも述べた通り、関数を変数として定義します。
定義は下記のようになります。

private delegate void TestProcess(string str);

変数名は【TestProcess】という名前で、引数は文字列で、戻り値がない関数を変数として定義。

使用例(実行)

インスタンスを生成して、使用するパタンを紹介します。

下記関数を作成しました。

private void 関数A(string dt)
{
    //----- 処理 -----//
}

上記作成した関数Aを実行する為に下記のような記載をします。

TestProcess _test = new TestProcess([関数A]);
_test("[文字列]");

引数が文字列で戻り値のない関数Aを_testという名前で定義します。
そして、_testに引数の文字列を引き渡すと、関数Aが実行されます。

使用例(引数)

引数として使うパタンを紹介します。
このパタンは、関数を統一したい場合に使用できます。

まずは、関数を定義・作成します。

private void 関数A(string dt)
{
    //----- 処理 -----//
}

private void 関数B(TestProcess proc)
{
    proc("[文字列]");
}

ここで定義した関数Bを使って、関数Aを実行するようにします。

関数B(関数A);

引数の中に関数名をいれるのは、ちょっと斬新ですね。

サンプルの作成

用途的にちょっと微妙だが、今回のサンプルは、下記の通りに作成する。
ボタンを押されると、テキストボックスに入力されている『行数を取得』or『文字数を取得』を取得する。もしくは両方を行う。

操作画面

簡単にコントロールの説明

textBox1  :入力文字
btnGetRow  :行数を取得する。取得した内容はlabel1に表示する。
btnGetLength:文字数を取得する。取得した内容はlabel2に表示する。
btnBoth   :行数&文字数を取得する。取得した内容はlabel1/label2に表示する。
btnReset  :label1/label2の表示を空白にする。
label1   :行数表示用
label2   :文字数表示用

定義

まずは、フォーム内で使用する為のデリゲートを定義する。

private delegate void TestProcess(string str);

そして、「行数取得し、label1に表示する関数」を作成する。

private void GetRows(string dt)
{
    //リターンで配列で分けて、その数を取得する。
    int rows = dt.Split('\n').Length;  
    label1.Text = rows.ToString();
}

次に、「文字数を取得し、label2に表示する関数」を定義する。

private void GetLength(string dt)
{
    //文字数を取得する。
    int num = dt.Length;
    label2.Text = num.ToString();
}

最後に、『引数で実行できるパタンの関数』を定義する。

private void test(string dt,TestProcess proc)
{
    proc(dt);
}

処理の紹介

行数取得ボタンの処理

行数の取得のボタン[btnGetRow]がクリックされた時の処理

private void btnGetRow_Click(object sender, EventArgs e)
{
    //instanceを生成して実行するパタン
    TestProcess _getrow = new TestProcess(GetRows);
    _getrow(textBox1.Text);

    //引数で引き渡して実行するパタン
    //test(textBox1.Text, GetRows);
}

行数取得の時は、インスタンスを生成してからの実行するパタンである。
コメントアウトしてあるが、関数の引数として渡すパタンも紹介しており、結果は同じである。

文字数取得ボタンの処理

文字数の取得のボタン[btnGetLength]がクリックされた時の処理

private void btnGetLength_Click(object sender, EventArgs e)
{
    //instanceを生成して実行するパタン
    //TestProcess _getlen = new TestProcess(GetLength);
    //_getlen(textBox1.Text);

    //引数で引き渡して実行するパタン
    test(textBox1.Text, GetLength);
}

定義した関数で引数に渡したパタンです。

両方[行数&文字数取得]ボタンの処理  ★マルチキャストデリゲートを使う

インスタンスを生成した場合、複数の関数を同時(順次)に実行できるようにできます。
これを「マルチキャストデリゲート」と呼ぶらしいです。
書き方的にはとても便利です。

private void btnBoth_Click(object sender, EventArgs e)
{
    //行数取得の関数を生成する。
    TestProcess _proc = new TestProcess(GetRows);

    //文字数取得の関数を追加する。
    _proc += GetLength;

    //実行する。
    _proc(textBox1.Text);

    //引数で引き渡して実行するパタン
    //test(textBox1.Text, GetRows);
    //test(textBox1.Text, GetLength);
}

イベント処理の追加/削除の時も同じことをしますが、[+=]/[-=]を使って追加/削除をすることが可能です。
定義した関数を使った方が、2行で終わりますが、同じ引数を渡すことを考えると、3行になってしまいましたが、スマートにはなっています。※個人の価値観

実行結果

動作していそうです。[キャリッジ][リターン]も各々1文字として数えるため、文字数が多くなっていますが、正確に出力されていそうです。

まとめ

今回は、delegate[デリゲート]を紹介しました。
関数を変数のように使えるのはとても便利な事だと思います。
しかし、過去の自分の作成したソフトでは使用した記憶ははありません。
ちなみに、人が作ったソフトを修正する時に使用されていたことがありあり、人のソフトを読むときに、使い方や概要を理解していないと読み解くことが苦労してしまいます。
また、今まで作っていたソフトで、delegateを使っておけば。。。ってパタンをありますね。

補足

リセットボタンの処理

内容として関係なかったので、最後に補足として紹介します。
リセットボタン[btnReset]の処理は下記の通りです。

private void btnReset_Click(object sender, EventArgs e)
{
    label1.Text = label2.Text = "";
}

コメント

タイトルとURLをコピーしました