いろいろ備忘録日記

主に .NET と Python絡みのメモを公開しています。

C#3.0の追加機能-03(ラムダ式(lambda))


C# 3.0からラムダ式を作成出来るようになりました。pythonを使っている人には
おなじみのものですね。


ちなみにpythonの場合は、以下のようにしてラムダ式を作成します。

f = lambda x: x * x
f(2)


同じものをC#で書くと以下のようになります。

Func<int, int> f = x => { return x * x; };
Console.WriteLine(f(2));


上記の部分で

x => { return x * x; };

となっている部分がラムダ式です。C# 2.0の場合は以下のように記述していました。

Func<int, int> f = delegate(int x){ return x * x; };
Console.WriteLine(f(2));


ラムダ式は、匿名デリゲートをもう少し簡便に記述できるようになったという雰囲気だと
思うと分かりやすいです。なので、Array.ForEachなどが書きやすくなります。

Array.ForEach(Array.ConvertAll(new[]{"hoge", "hehe", "fuga"}, elem => { return elem.ToUpper(); }), elem => { Console.WriteLine(elem); });

上の例は匿名デリゲートを使用しても同じものが記述できますが、ラムダ式で記述したほうが個人的には見やすいです。


また、ラムダ式を利用することでクロージャー(Closure)を書くことが出来ます。(匿名デリゲートでも出来ますが・・)

Func<int, Func<int, int>> MakeClosure = x => { return y => { return x + y; }; };

Func<int, int> closure  = MakeClosure(10);
Func<int, int> closure2 = MakeClosure(20);

Console.WriteLine(closure(100));
Console.WriteLine(closure2(100));

上記を実行すると、110, 120となります。
ちゃんとクロージャーを作成した際に渡した本来ならスコープ外の値も保持されていますね。(関数閉包)



てことで、以下サンプルです。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;

namespace Gsf.Samples.Tmp{

    public class LambdaExpressionSample : IExecutor{

        public void Execute(){
            //
            // 普通にラムダ式を作成.
            //
            Func<int, int> f = x => { return x * x; };
            Console.WriteLine(f(2));

            //
            // Array.ForEachとArray.ConvertAllのデリゲートにラムダ式を指定.
            //
            Array.ForEach(Array.ConvertAll(new[]{"hoge", "hehe", "fuga"}, elem => { return elem.ToUpper(); }), elem => { Console.WriteLine(elem); });

            //
            // クロージャーを作成.
            //
            Func<int, Func<int, int>> MakeClosure = x => { return y => { return x + y; }; };

            Func<int, int> closure  = MakeClosure(10);
            Func<int, int> closure2 = MakeClosure(20);

            Console.WriteLine(closure(100));
            Console.WriteLine(closure2(100));
        }
    }
}


ちなみに、ラムダ式や匿名デリゲートでは一旦作成したデリゲートを保持しておく際に
以下のジェネリックデリゲートが良く使われます。

  • System.Func
  • System.Func
  • System.Action
  • System.Action(T)
  • System.Predicate(T)


上記の内、Funcジェネリックデリゲートは.NET Framework 3.5で登場しました。
System.Core.dll内に存在しています。
また、Func,Actionデリゲートは共に、引数を4つまで受け取れるよう
複数定義されています。