【C#】デリゲートを定義して使用する方法

C#における「デリゲート」は「ラムダ式」「LINQ」へとつながる重要な技術です。そのため、当ブログでは「【C#】デリゲートとは | 関数・メソッドをカプセル化する機能」にて基礎知識を解説しました。

この記事では上記で紹介しているデリゲートについて、サンプルを交えながら使い方を解説していきます。ラムダ式やLINQにつながる重要なテーマなので、しっかりと理解しておくことが望ましいです。

デリゲートの使い方

それではデリゲートを記述していきます。コンソールアプリケーションで作成しました。

using System;

namespace App01
{
    class Program
    {
        // デリゲートの宣言部分
        delegate void Output(string name);

        // デリゲートの実処理部分
        private static void WriteHello(string name)
        {
            Console.WriteLine($"Hello, { name }!");
        }

        // メイン処理実行部分
        static void Main(string[] args)
        {
            Console.WriteLine("ログイン名を入力してください。");
            var name = Console.ReadLine();

            //Output型の変数として「WriteHello」の処理内容を設定する
            Output process = WriteHello;
            //デリゲートを実行する
            process(name);

            Console.ReadLine();
        }
    }
}

画面上の「開始」ボタンを押下してコンソールアプリケーションを実行してみましょう。

Hello, 〇〇(入力した名称)!

適当に名称を入力して、以下のようにコンソール上にメッセージが表示されたら成功です。なお、最初に生成されるデフォルトコードから「Usingの削除と並び替え(ctrl + R → ctrl + G)」を行って、処理に不要な参照を削除しています。

delegate型の変数を定義する

delegate型の変数を定義して、メソッドを格納するための箱を作成していきます。該当部分は以下の部分になります。

// デリゲートの宣言部分
delegate void Output(string name);

今回はシンプルにメッセージをコンソールに表示させるだけなので、戻り値を不要とし引数として文字列を1つ受け付けるようにしています。これでdelegate型の変数の定義は完了です。

delegateの処理内容を記述する

定義したデリゲート変数に対応する処理部分は、変数で定義した戻り値と引数を持つメソッドを用意することで記述できます。先ほどの変数では以下のようにシグネチャを記述しました。

  • void型である
  • string型の引数を1つ取る

上記の2つを満たすメソッドを記述すれば、先ほどの「Output」に適応可能になります。先ほどのコードでは以下の部分が該当します。

// デリゲートの実処理部分
private static void WriteHello(string name)
{
    Console.WriteLine($"Hello, { name }!");
}

ここまで記述してデリゲートの処理部分と、デリゲート型の変数の準備は完了です。次は作成したデリゲートの処理を実行する部分を記述していきます。

デリゲートの実行を記述する

デリゲートの実行部分では、簡単にするために一度変数に代入して参照できる形式にして、メソッドを実行するようにしています。該当する部分は以下の記述になります。

//Output型の変数として「WriteHello」の処理内容を設定する
Output process = WriteHello;

「Output process」の記述でデリゲートを定義して、「= WriteHello;」の箇所で定義したメソッドを参照できる形式でカプセル化しています。定義したOutput型とWriteHelloのシグネチャが合致していることを確認してください。

デリゲートをカプセル化する作業は完了したので、次は実際にデリゲートを実行していきます。コード内の以下の部分が実行箇所になります。

//デリゲートを実行する
process(name);

「WriteHello」メソッドを「process」という変数に代入しており、「process」からデリゲートの処理が実行できます。「process」の実処理部分は「WriteHello」であるため、宣言しているとおり引数が必要ですので、「(name)」で引数を渡しています。そのうえで「process」を通常のメソッドと同様に実行します。

Hello, 〇〇(入力した名称)!

実行結果は上記の通りです。デリゲートは変数として、処理部分をカプセル化するので、これまでの「変数は値」から思考を切り替える必要があります。今後は「変数」をみたら「型」を確認して、それが「値なのかデリゲートなのか」を知っておく必要があるということです。

デリゲートは処理をカプセル化する

この記事では「デリゲート」の基礎を紹介してきました。「デリゲート」に簡単にまとめると以下のようになります。

  • delegateキーワードを使用して定義する
  • delegateの定義に沿った処理部分を記述する
  • delegateは処理をカプセル化して変数に閉じ込める

この中で最も重要なのが3つ目の「delegateは処理をカプセル化して変数に閉じ込める」になります。この考え方が「ラムダ式」からLINQの根底になります。カプセル化することで「処理を必要な時に実行できる」「処理を可変的に代入できる」という利点を得ることができます。

この考え方がすべての始まりになります。これまで「変数といえば値」と考えていた人は、「変数は処理そのものを持っている可能性がある」と思考を切り替える必要があります。これがラムダ式を理解するうえで重要な「視点」となります。