ラムダ式 (C# プログラミング ガイド)Lambda Expressions (C# Programming Guide)

ラムダ式は、 デリゲート 型または 式ツリー 型を作成するために使用できる 匿名関数 です。A lambda expression is an anonymous function that you can use to create delegates or expression tree types. ラムダ式を使用すると、引数として渡したり関数呼び出しの結果値として返すことができるローカル関数を記述できます。By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls. ラムダ式は、LINQ クエリ式を記述する場合に特に便利です。Lambda expressions are particularly helpful for writing LINQ query expressions.

ラムダ式を作成するには、ラムダ演算子 ( =>) の左側に入力パラメーター (ある場合) を指定し、反対側に式またはステートメント ブロックを置きます。To create a lambda expression, you specify input parameters (if any) on the left side of the lambda operator =>, and you put the expression or statement block on the other side. たとえば、ラムダ式 x => x * x は、 x という名前のパラメーターを指定し、 x を 2 乗した値を返します。For example, the lambda expression x => x * x specifies a parameter that’s named x and returns the value of x squared. 次の例に示すように、この式をデリゲート型に割り当てることもできます。You can assign this expression to a delegate type, as the following example shows:

delegate int del(int i);  
static void Main(string[] args)  
{  
    del myDelegate = x => x * x;  
    int j = myDelegate(5); //j = 25  
}  

式ツリー型を作成するにはTo create an expression tree type:

using System.Linq.Expressions;  

namespace ConsoleApplication1  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Expression<del> myET = x => x * x;  
        }  
    }  
}  

=> 演算子は、代入 (=) と同じ優先順位であり、結合規則が右から左 です (演算子に関するドキュメントの「結合規則」を参照してください)。The => operator has the same precedence as assignment (=) and is right associative (see "Associativity" section of the Operators article).

ラムダは、LINQLINQ のメソッド ベースのクエリ内で標準クエリ演算子のメソッド (Where など) の引数として使用されます。Lambdas are used in method-based LINQLINQ queries as arguments to standard query operator methods such as Where.

メソッド ベースの構文を使用して ( Where to Objects および Enumerable の場合と同様に) LINQLINQ クラスの LINQ to XMLメソッドを呼び出すと、パラメーターはデリゲート型 System.Func<T,TResult>になります。When you use method-based syntax to call the Where method in the Enumerable class (as you do in LINQLINQ to Objects and LINQ to XML) the parameter is a delegate type System.Func<T,TResult>. ラムダ式はデリゲートを作成するための最も便利な方法です。A lambda expression is the most convenient way to create that delegate. たとえば (System.Linq.Queryable の場合と同様に) LINQ to SQLLINQ to SQL クラスの同じメソッドを呼び出すと、パラメーター型は System.Linq.Expressions.Expression<Func> になります。Func は最大 16 の入力パラメーターを持つ Func デリゲートです。When you call the same method in, for example, the System.Linq.Queryable class (as you do in LINQ to SQLLINQ to SQL) then the parameter type is an System.Linq.Expressions.Expression<Func> where Func is any of the Func delegates with up to sixteen input parameters. ラムダ式は、こうした式ツリーを構築するための非常に簡潔な方法でもあります。Again, a lambda expression is just a very concise way to construct that expression tree. ラムダを使用すると Where 呼び出しの外観を似たものにできますが、ラムダから実際に作成されるオブジェクトの型は異なります。The lambdas allow the Where calls to look similar although in fact the type of object created from the lambda is different.

先ほどの例では、デリゲート シグネチャは暗黙的に型指定される int型の入力パラメーターを 1 つ持ち、 intを返します。In the previous example, notice that the delegate signature has one implicitly-typed input parameter of type int, and returns an int. このラムダ式を同じ型のデリゲートに変換することができます。デリゲートも 1 つの入力パラメーター (x) を持ち、コンパイラが暗黙的に int 型に変換できる値を返すからです The lambda expression can be converted to a delegate of that type because it also has one input parameter (x) and a return value that the compiler can implicitly convert to type int. (型の推論については後のセクションで詳しく説明します)。入力パラメーターとして 5 を使用してデリゲートを呼び出すと、デリゲートは 25 という結果を返します。(Type inference is discussed in more detail in the following sections.) When the delegate is invoked by using an input parameter of 5, it returns a result of 25.

is 演算子または as 演算子の左辺にラムダを使用することはできません。Lambdas are not allowed on the left side of the is or as operator.

匿名メソッドに適用される制限は、すべてラムダ式にも適用されます。All restrictions that apply to anonymous methods also apply to lambda expressions. 詳細については、「匿名メソッド」を参照してください。For more information, see Anonymous Methods.

式形式のラムダExpression Lambdas

=> 演算子の右辺に式があるラムダ式を "式形式のラムダ" と呼びます。A lambda expression with an expression on the right side of the => operator is called an expression lambda. 式形式のラムダは、式ツリーの構築に幅広く使用されます。Expression lambdas are used extensively in the construction of Expression Trees. 式形式のラムダは式の結果を返します。基本的な形式は次のとおりです。An expression lambda returns the result of the expression and takes the following basic form:

(input-parameters) => expression

かっこはラムダの入力パラメーターが 1 つの場合のみ省略可能で、それ以外の場合は必須です。The parentheses are optional only if the lambda has one input parameter; otherwise they are required. 入力パラメーターが 2 つ以上ある場合は、かっこで囲んで各パラメーターをコンマで区切ります。Two or more input parameters are separated by commas enclosed in parentheses:

(x, y) => x == y

コンパイラが入力の型を推論するのが困難または不可能な場合もあります。Sometimes it is difficult or impossible for the compiler to infer the input types. このような場合は、次の例のように型を明示的に指定できます。When this occurs, you can specify the types explicitly as shown in the following example:

(int x, string s) => s.Length > x

入力パラメーターがないことを指定するには、次のように空のかっこを使用します。Specify zero input parameters with empty parentheses:

() => SomeMethod()

この例では、式形式のラムダの本体をメソッド呼び出しで構成できることに注目してください。Note in the previous example that the body of an expression lambda can consist of a method call. ただし、SQL Server など .NET Framework の外部で評価される式ツリーを作成する場合は、ラムダ式内でメソッド呼び出しを使用することはできません。However, if you are creating expression trees that are evaluated outside of the .NET Framework, such as in SQL Server, you should not use method calls in lambda expressions. .NET 共通言語ランタイムのコンテキストの外部では、これらのメソッドは通用しません。The methods will have no meaning outside the context of the .NET common language runtime.

ステートメント形式のラムダStatement Lambdas

ステートメント形式のラムダは式形式のラムダに似ていますが、ステートメントが中かっこで囲まれる点が異なります。A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:

(input-parameters) => { statement; }(input-parameters) => { statement; }

ステートメント形式のラムダの本体は任意の数のステートメントで構成できますが、実際面では通常、2、3 個以下にします。The body of a statement lambda can consist of any number of statements; however, in practice there are typically no more than two or three.

delegate void TestDelegate(string s);
TestDelegate del = n => { string s = n + " World"; 
                          Console.WriteLine(s); };

匿名メソッドと同様、ステートメント形式のラムダを使用して式ツリーを作成することはできません。Statement lambdas, like anonymous methods, cannot be used to create expression trees.

非同期ラムダAsync Lambdas

async キーワードと await キーワードを使用すると、非同期処理を組み込んだラムダ式およびステートメントを簡単に作成できます。You can easily create lambda expressions and statements that incorporate asynchronous processing by using the async and await keywords. たとえば、次に示す Windows フォーム例には、非同期メソッド ExampleMethodAsyncを呼び出して待機するイベント ハンドラーが含まれています。For example, the following Windows Forms example contains an event handler that calls and awaits an async method, ExampleMethodAsync.

public partial class Form1 : Form  
{  
    public Form1()  
    {  
        InitializeComponent();  
    }  

    private async void button1_Click(object sender, EventArgs e)  
    {  
        // ExampleMethodAsync returns a Task.  
        await ExampleMethodAsync();  
        textBox1.Text += "\r\nControl returned to Click event handler.\n";  
    }  

    async Task ExampleMethodAsync()  
    {  
        // The following line simulates a task-returning asynchronous process.  
        await Task.Delay(1000);  
    }  
}  

非同期ラムダを使用して、同じイベント ハンドラーを追加できます。You can add the same event handler by using an async lambda. 次の例に示すように、このハンドラーを追加するには、ラムダ パラメーター リストの前に async 修飾子を追加します。To add this handler, add an async modifier before the lambda parameter list, as the following example shows.

public partial class Form1 : Form  
{  
    public Form1()  
    {  
        InitializeComponent();  
        button1.Click += async (sender, e) =>  
        {  
            // ExampleMethodAsync returns a Task.  
            await ExampleMethodAsync();  
            textBox1.Text += "\nControl returned to Click event handler.\n";  
        };  
    }  

    async Task ExampleMethodAsync()  
    {  
        // The following line simulates a task-returning asynchronous process.  
        await Task.Delay(1000);  
    }  
}  

非同期メソッドの作成および使用方法の詳細については、「Async および Await を使用した非同期プログラミング」を参照してください。For more information about how to create and use async methods, see Asynchronous Programming with async and await.

標準クエリ演算子でのラムダLambdas with the Standard Query Operators

標準クエリ演算子の多くが、汎用デリゲートの Func<T,TResult> ファミリに属する型の入力パラメーターを持ちます。Many Standard query operators have an input parameter whose type is one of the Func<T,TResult> family of generic delegates. これらのデリゲートは型パラメーターを使用して入力パラメーターの数と型、およびデリゲートの戻り値の型を定義します。These delegates use type parameters to define the number and types of input parameters, and the return type of the delegate. Func デリゲートは、ソース データのセット内の各要素に適用されるユーザー定義の式をカプセル化する場合に非常に便利です。Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. たとえば、次のデリゲート型を考えてみましょう。For example, consider the following delegate type:

public delegate TResult Func<TArg0, TResult>(TArg0 arg0)  

このデリゲートを Func<int,bool> myFunc としてインスタンス化できます。 int は入力パラメーター、 bool は戻り値です。The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. 戻り値は必ず最後の型パラメーターで指定されます。The return value is always specified in the last type parameter. Func<int, string, bool> は 2 つの入力パラメーター ( intstring) と戻り値の型 boolを持つデリゲートを定義しています。Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. 次の Func デリゲートを呼び出すと、入力パラメーターが 5 に等しいかどうかを示す true または false が返されます。The following Func delegate, when it is invoked, will return true or false to indicate whether the input parameter is equal to 5:

Func<int, bool> myFunc = x => x == 5;  
bool result = myFunc(4); // returns false of course  

たとえば System.Linq.Queryable で定義された標準クエリ演算子において、引数型が Expression<Func>の場合もラムダ式を使用できます。You can also supply a lambda expression when the argument type is an Expression<Func>, for example in the standard query operators that are defined in System.Linq.Queryable. Expression<Func> 引数を指定すると、ラムダは式ツリーにコンパイルされます。When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.

標準クエリ演算子である Count メソッドを次に示します。A standard query operator, the Count method, is shown here:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };  
int oddNumbers = numbers.Count(n => n % 2 == 1);  

入力パラメーターの型はコンパイラが推論できますが、明示的に指定することもできます。The compiler can infer the type of the input parameter, or you can also specify it explicitly. この特定のラムダ式は、2 で除算したときに剰余が 1 になる整数 (n) をカウントします。This particular lambda expression counts those integers (n) which when divided by two have a remainder of 1.

次のメソッドは、配列 numbers 内で 9 より左側にある要素をすべて含むシーケンスを作成します。これは、9 がシーケンス内で条件を満たさない最初の数値であるためです。The following line of code produces a sequence that contains all elements in the numbers array that are to the left side of the 9 because that's the first number in the sequence that doesn't meet the condition:

var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);  

次の例は、複数の入力パラメーターをかっこで囲んで指定する方法を示しています。This example shows how to specify multiple input parameters by enclosing them in parentheses. このメソッドは、値がその位置よりも小さい数値が出現するまで配列 numbers に含まれるすべての要素を返します。The method returns all the elements in the numbers array until a number is encountered whose value is less than its position. ラムダ演算子 (=>) と以上演算子 (>=) を混同しないようにしてください。Do not confuse the lambda operator (=>) with the greater than or equal operator (>=).

var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);  

ラムダにおける型の推論Type Inference in Lambdas

ラムダを記述する際、多くの場合は入力パラメーターの型を指定する必要はありません。これは、ラムダ本体やパラメーターのデリゲート型など C# 言語仕様に記述されている要素に基づいて、コンパイラが型を推論できるためです。When writing lambdas, you often do not have to specify a type for the input parameters because the compiler can infer the type based on the lambda body, the parameter’s delegate type, and other factors as described in the C# Language Specification. ほとんどの標準クエリ演算子では、最初の入力がソース シーケンス内の要素の型です。For most of the standard query operators, the first input is the type of the elements in the source sequence. したがって、 IEnumerable<Customer>を問い合わせると、入力変数は Customer オブジェクトであると推論されます。これは、そのメソッドとプロパティにアクセスできることを意味します。So if you are querying an IEnumerable<Customer>, then the input variable is inferred to be a Customer object, which means you have access to its methods and properties:

customers.Where(c => c.City == "London");  

ラムダの一般規則は、次のとおりです。The general rules for lambdas are as follows:

  • ラムダにはデリゲート型と同じ数のパラメーターが含まれていなければなりません。The lambda must contain the same number of parameters as the delegate type.

  • ラムダに含まれる各入力パラメーターは、対応するデリゲート パラメーターに暗黙的に変換できなければなりません。Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.

  • ラムダの戻り値 (ある場合) は、デリゲートの戻り値の型に暗黙的に変換できなければなりません。The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.

共通型システムには "ラムダ式" の概念が組み込まれていないため、ラムダ式自体は型を持ちません。Note that lambda expressions in themselves do not have a type because the common type system has no intrinsic concept of "lambda expression." しかし、変則的ではあってもラムダ式の "型" を表現できると都合が良い場合もあります。However, it is sometimes convenient to speak informally of the "type" of a lambda expression. このような場合の型は、ラムダ式の変換後のデリゲート型または Expression 型を指します。In these cases the type refers to the delegate type or Expression type to which the lambda expression is converted.

ラムダ式における変数のスコープVariable Scope in Lambda Expressions

ラムダは、"外部変数" を参照できます (「匿名メソッド」を参照)。外部変数とは、ラムダ関数を定義するメソッド内のスコープ、またはラムダ式を含む型のスコープに存在する変数のことです。Lambdas can refer to outer variables (see Anonymous Methods) that are in scope in the method that defines the lambda function, or in scope in the type that contains the lambda expression. こうして取り込まれた変数は、ラムダ式で使用するために格納されます。これは、変数がスコープ外に出てガベージ コレクトされる場合でも変わりません。Variables that are captured in this manner are stored for use in the lambda expression even if the variables would otherwise go out of scope and be garbage collected. 外部変数は、ラムダ式で使用される前に明示的に代入する必要があります。An outer variable must be definitely assigned before it can be consumed in a lambda expression. 次の例は、こうした規則を示しています。The following example demonstrates these rules:

delegate bool D();  
delegate bool D2(int i);  

class Test  
{  
    D del;  
    D2 del2;  
    public void TestMethod(int input)  
    {  
        int j = 0;  
        // Initialize the delegates with lambda expressions.  
        // Note access to 2 outer variables.  
        // del will be invoked within this method.  
        del = () => { j = 10;  return j > input; };  

        // del2 will be invoked after TestMethod goes out of scope.  
        del2 = (x) => {return x == j; };  

        // Demonstrate value of j:  
        // Output: j = 0   
        // The delegate has not been invoked yet.  
        Console.WriteLine("j = {0}", j);        // Invoke the delegate.  
        bool boolResult = del();  

        // Output: j = 10 b = True  
        Console.WriteLine("j = {0}. b = {1}", j, boolResult);  
    }  

    static void Main()  
    {  
        Test test = new Test();  
        test.TestMethod(5);  

        // Prove that del2 still has a copy of  
        // local variable j from TestMethod.  
        bool result = test.del2(10);  

        // Output: True  
        Console.WriteLine(result);  

        Console.ReadKey();  
    }  
}  

ラムダ式における変数のスコープには、次の規則が適用されます。The following rules apply to variable scope in lambda expressions:

  • 取り込まれた変数は、その変数を参照するデリゲートがガベージ コレクションの対象になるまでガベージ コレクトされません。A variable that is captured will not be garbage-collected until the delegate that references it becomes eligible for garbage collection.

  • ラムダ式内に導入された変数は、外側のメソッドでは参照できません。Variables introduced within a lambda expression are not visible in the outer method.

  • ラムダ式は、外側のメソッドの ref パラメーターまたは out パラメーターを直接取り込むことはできません。A lambda expression cannot directly capture a ref or out parameter from an enclosing method.

  • ラムダ式に含まれる return ステートメントで外側のメソッドを戻すことはありません。A return statement in a lambda expression does not cause the enclosing method to return.

  • ラムダ式には、 goto ステートメント、 break ステートメント、およびジャンプ ステートメントのジャンプ先がブロック外である場合はラムダ式の内部にある continue ステートメントを含めることはできません。A lambda expression cannot contain a goto statement, break statement, or continue statement that is inside the lambda function if the jump statement’s target is outside the block. また、ジャンプ先がブロックの内部にある場合は、ラムダ式の外部でジャンプ ステートメントを使用するとエラーになります。It is also an error to have a jump statement outside the lambda function block if the target is inside the block.

C# 言語仕様C# Language Specification

詳細については、「C# 言語の仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。

C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers (C# 3.0 クックブック (第 3 版): C# 3.0 プログラマ向けの 250 以上のソリューション)』の「Delegates, Events, and Lambda Expressions (デリゲート、イベント、およびラムダ式)Delegates, Events, and Lambda Expressions in C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers

関連項目See Also

C# プログラミング ガイドC# Programming Guide
統合言語クエリ (LINQ)LINQ (Language-Integrated Query)
匿名メソッドAnonymous Methods
isis
式ツリーExpression Trees
Visual Studio 2008 c# Samples (「LINQ サンプル クエリでファイルと XQuery プログラム)Visual Studio 2008 C# Samples (see LINQ Sample Queries files and XQuery program)
Recursive lambda expressions (再帰的なラムダ式)Recursive lambda expressions