C#でデリゲートを使って遊んだ


C#でデリゲートやラムダ式など使い、いろいろ遊んでみました

program.cs
using System;

namespace CsLamTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int> addDelegate=(        //(1)
                ()=> {                     //(1-1)
                    Console.WriteLine("初期化の関数から出力");     //(1-2)
                    return 0; 
                    }
                );

            f(                             //(2)
                () => {                    //(2-1)
                    Console.WriteLine("ラムダ式から出力");      //(2-2)
                    return 5 * 5;
                    },
                ref addDelegate           //(2-3)
            );
            f(                             //(3)
                delegate () {              //(3-1)
                    Console.WriteLine("デリゲートから出力");     //(3-2)
                    return 3 * 3;
                    },
                ref addDelegate          //(3-3)
            );
        }

        static void f(Func<int> func, ref Func<int> addDelegate)  //(4)
        {
            addDelegate += func;            //(4-1)
            Console.WriteLine(addDelegate());     //(4-2)
        }
    }
}

出力結果は

初期化の関数から出力
ラムダ式から出力
25
初期化の関数から出力
ラムダ式から出力
デリゲートから出力
9

解説

まずは(1)の部分

program.cs
            Func<int> addDelegate=(        //(1)
                ()=> {                     //(1-1)
                    Console.WriteLine("初期化の関数から出力");     //(1-2)
                    return 0; 
                    }
                );

(1)の行は、Func<int>(引数を取らずint型を返す関数)型のaddDelegateを定義しています。
addDelegateの初期化が(1-1)でラムダ式を用いて行われています。


次に(2)の部分

program.cs
            f(                             //(2)
                () => {                    //(2-1)
                    Console.WriteLine("ラムダ式から出力");      //(2-2)
                    return 5 * 5;
                    },
                ref addDelegate           //(2-3)
            );

(2)(4)の関数fを呼び出しています。
その第1引数Func<int> func(2-1)で示されたラムダ式を渡しています。
第2引数ref Func<int> addDelegate(1)addDelegateを渡しています。・・・(2-3)の行。

(3)はラムダ式ではなく無名関数を渡しています。他は(2)と同じです。


次に(4)の部分

program.cs
        static void f(Func<int> func, ref Func<int> addDelegate)  //(4)
        {
            addDelegate += func;            //(4-1)
            Console.WriteLine(addDelegate());     //(4-2)
        }

(4-1)で、第1引数で渡されたfuncを、第2引数で渡されたaddDelegateに加えています。
デリゲートは、+=演算子を用いて、関数を連結できます。
連結された関数は、古いものから順番に実行されます。

実行の流れ

  1. まず(2)で関数fを呼び出し
  2. (4-1)addDelegate(2-1)のラムダ式を加える
  3. (4-2)addDelegate()を実行

    1. (1-2)が出力される
    2. (2-2)が出力される
    3. (2-1)のラムダ式の戻り値が出力される。
  4. 次に(3)で関数fを呼び出し

  5. (4-1)addDelegate(3-1)のデリゲートを加える

  6. 3.と同じ

    1. (1-2) (2-2) (3-2) が順番に出力される
    2. (3-1)のデリゲートの戻り値が出力される

今回のC#いじりで知ったこと

Func<int>には、ラムダ式も無名関数も渡せる、代入できる。
Console.WriteLine()では、デリゲートに複数の関数が+=で連結されていても、最後に実行される関数の戻り値のみ表示する。
デリゲートは値型だった。なので、refをつけています。