hakeの日記

Windows環境でプログラミングの勉強をしています。

C# - デリゲート

デリゲートとは要するにラムダ式をいれるデリーゲート型変数を定義して使用する仕組み。
デリゲート型は以下のように定義する。

    delegate 戻り値型 デリゲート型(引数型と引数名リスト);

あるデリゲート型で宣言したデリゲート変数は、その型で定義された戻り値と引数リストを持つメソッドやラムダ式を格納できる。

    デリゲート型  変数名  = メソッド名;
    デリゲート型  変数名  = ラムダ式;

これだけだと、既に定義されているActionなどのデリゲート型だけを使用すれば良いが、面白いのは複数のメソッドやラムダ式を格納できること。

    デリゲート型  変数名  = メソッド名;
    変数  +=  ラムダ式;
    変数  -=  メソッド;      

名前がついているメソッドの場合は削除することもできる。この変数に引数リストをつけて実行すると、格納したメソッドやラムダ式が格納順に実行される。

    変数(引数リスト);

ただし戻り値のあるデリゲート型の変数の場合は、最後に登録したメソッドやラムダ式の戻り値のみが、全体の戻り値として返される。このため登録した全てのメソッドやラムダ式の戻り値を取得したい場合は、コレクションを引数にして処理結果を追加し、それを戻り値とする様な方法にする必要がある。(もっと適切な方法があるかも……)

using System;
using System.Collections.Generic;

//デリゲート

//stringを引数とし、値を返さないメソッドを格納できるデリゲート
delegate void MyDelegate1(string s);

//2つのintを引数とし、intを返すメソッドを格納できるデリゲート
delegate int MyDelegate2(int x, int y);

//List<int>と2つのintを引数とし、List<int>を返すメソッドを格納できるデリゲート
delegate List<int> MyDelegate3(List<int> a, int x, int y);


class MyMain
{
    public static void Main(string[] args)
    {
        Console.WriteLine("値を返さないデリゲート");
        Console.WriteLine("MyMSG1メソッド追加");
        MyDelegate1 md1 = MyMSG1;
        md1("TARO");    //Hello TARO
        Console.WriteLine("MyMSG2メソッド追加");
        md1 += MyMSG2;
        md1("TARO");    //Hello TARO
                        //Good bye TARO
        Console.WriteLine("MyMSG1メソッド削除");
        md1 -= MyMSG1;
        md1("TARO");    //Good bye TARO



        Console.WriteLine("-----");
        Console.WriteLine("int型の値を返すデリゲート");
        MyDelegate2 md2;

        Console.WriteLine("足し算メソッド追加");
        md2 = (x, y)  => x + y;
        Console.WriteLine("  実行:{0}", md2(2, 3) );

        Console.WriteLine("引き算メソッド追加");
        md2 += (x, y) => x - y;

        //最後に実行したメソッドの戻り値のみが返される
        Console.WriteLine("  実行:{0}", md2(2, 3) );



        Console.WriteLine("-----");
        List<int> a = new List<int>();
        
        Console.WriteLine("List<int>を返すデリゲート");
        MyDelegate3 md3;

        Console.WriteLine("足し算メソッド追加(計算結果をListに追加する)");
        md3 = (v, x, y)  => {v.Add(x + y); return v;};

        Console.WriteLine("引き算メソッド追加(計算結果をListに追加する)");
        md3 += (v, x, y)  => {v.Add(x - y); return v;};

        Console.Write("  実行: ");
        md3(a, 20, 30);
        //最後に実行したメソッドの戻り値のみが返される
        a.ForEach( e => Console.Write(e + " ") );
        Console.WriteLine();
        
    }

    private static void MyMSG1(string s)
    {
        Console.WriteLine("  Hello {0}", s);
    }
    private static void MyMSG2(string s)
    {
        Console.WriteLine("  Good bye {0}", s);
    }
}

 

実行結果

値を返さないデリゲート
MyMSG1メソッド追加
  Hello TARO
MyMSG2メソッド追加
  Hello TARO
  Good bye TARO
MyMSG1メソッド削除
  Good bye TARO
-----
int型の値を返すデリゲート
足し算メソッド追加
  実行:5
引き算メソッド追加
  実行:-1
-----
List<int>を返すデリゲート
足し算メソッド追加(計算結果をListに追加する)
引き算メソッド追加(計算結果をListに追加する)
  実行: 50 -10