Action<T>を使い倒してみる

Actionは『T型の引数を一つとり返値が無い関数』を意味するdelegate型である。System.Windows.Formsに定義されている。

delegate void Action<T>(T obj);

さてコンソールへメッセージを簡単に出力するConsole.Writeの使用方法を良く見てみると・・・

Console.Write("test");

これは『string型の引数を一つとり返値が無い』関数になっていることがわかる。つまりAction型であり、Action型の変数へ代入して使用することが出来ることを意味する。まあこの程度は余裕だろう。

Action<string> x;
x = Console.Write;
x("test");

ではAction>の意味はわかるだろうか?これは日本語で書くと『【string型の引数を一つとり返値が無い】関数を受け取り返値が無い関数』となる。

Action<Action<string>> x;
x = delegate(Action<string> p) { p("test"); };
x(Console.Write);

さてこのActionの入れ子定義をどんどん突き進めると以下のようになる。実行すると"test"というメッセージが7行コンソールに出力される。なかなか興味深い成長をしていく。こういうフラクタルなものに私は強く魅かれる。自動でx100とか出力するプログラムを作ると楽しそうだ。

using System;
using System.Windows.Forms;

namespace garu.testApp
{
    static class testApp
    {
        static void Main(string[] args)
        {
            Action<string> x1 = Console.WriteLine;
            x1("test");

            Action<Action<string>> x2 =
            delegate(Action<string> p1)
            {
                p1("test");
            };
            x2(Console.WriteLine);

            Action<Action<Action<string>>> x3 =
            delegate(Action<Action<string>> p1)
            {
                p1(Console.WriteLine);
            };
            x3(delegate(Action<string> p1)
            {
                p1("test");
            });

            Action<Action<Action<Action<string>>>> x4 =
            delegate(Action<Action<Action<string>>> p1)
            {
                p1(delegate(Action<string> p2)
                {
                    p2("test");
                });
            };
            x4(delegate(Action<Action<string>> p1)
            {
                p1(Console.WriteLine);
            });

            Action<Action<Action<Action<Action<string>>>>> x5 =
            delegate(Action<Action<Action<Action<string>>>> p1)
            {
                p1(delegate(Action<Action<string>> p2)
                {
                    p2(Console.WriteLine);
                });
            };
            x5(delegate(Action<Action<Action<string>>> p1)
            {
                p1(delegate(Action<string> p2)
                {
                    p2("test");
                });
            });

            Action<Action<Action<Action<Action<Action<string>>>>>> x6 =
            delegate(Action<Action<Action<Action<Action<string>>>>> p1)
            {
                p1(delegate(Action<Action<Action<string>>> p2)
                {
                    p2(delegate(Action<string> p3)
                    {
                        p3("test");
                    });
                });
            };
            x6(delegate(Action<Action<Action<Action<string>>>> p1)
            {
                p1(delegate(Action<Action<string>> p2)
                {
                    p2(Console.WriteLine);
                });
            });

            Action<Action<Action<Action<Action<Action<Action<string>>>>>>> x7 =
            delegate(Action<Action<Action<Action<Action<Action<string>>>>>> p1)
            {
                p1(delegate(Action<Action<Action<Action<string>>>> p2)
                {
                    p2(delegate(Action<Action<string>> p3)
                    {
                        p3(Console.WriteLine);
                    });
                });
            };
            x7(delegate(Action<Action<Action<Action<Action<string>>>>> p1)
            {
                p1(delegate(Action<Action<Action<string>>> p2)
                {
                    p2(delegate(Action<string> p3)
                    {
                        p3("test");
                    });
                });
            });

            Console.ReadLine();
        }
    }
}