Lambda-Ausdrücke (C#-Programmierhandbuch)Lambda Expressions (C# Programming Guide)

Ein Lambda-Ausdruck ist eine anonyme Funktion , mit der Typen für Delegaten oder die Ausdrucksbaumstruktur erstellt werden können.A lambda expression is an anonymous function that you can use to create delegates or expression tree types. Mit Lambda-Ausdrücken können lokale Funktionen geschrieben werden, die als Argumente übergeben oder als Wert von Funktionsaufrufen zurückgegeben werden können.By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls. Lambda-Ausdrücke sind besonders für das Schreiben von LINQ-Abfrageausdrücken hilfreich.Lambda expressions are particularly helpful for writing LINQ query expressions.

Zum Erstellen eines Lambda-Ausdrucks geben Sie Eingabeparameter (falls vorhanden) auf der linken Seite des Lambda-Operators =>an und stellen den Ausdruck oder den Anweisungsblock auf die andere Seite.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. Beispielsweise gibt der Lambda-Ausdruck x => x * x einen Parameter an, der x heißt und den Wert x quadriert zurückgibt.For example, the lambda expression x => x * x specifies a parameter that’s named x and returns the value of x squared. Dieser Ausdruck kann einem Delegattyp zuwiesen werden, wie im folgenden Beispiel dargestellt: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  
}  

So erstellen Sie einen Typ für die AusdrucksbaumstrukturTo create an expression tree type:

using System.Linq.Expressions;  

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

Der Operator => hat die gleiche Rangfolge wie Zuordnung (=) und ist rechtsassoziativ (siehe Abschnitt „Assoziativität“ im Artikel „Operatoren“).The => operator has the same precedence as assignment (=) and is right associative (see "Associativity" section of the Operators article).

Lambdas werden in methodenbasierten LINQLINQ-Abfragen als Argumente für Standardabfrageoperator-Methoden wie Where verwendet.Lambdas are used in method-based LINQLINQ queries as arguments to standard query operator methods such as Where.

Wenn Sie zum Aufrufen der Where -Methode in der Enumerable -Klasse methodenbasierte Syntax verwenden (wie in LINQLINQ to Objects und LINQ to XML), ist der Parameter ein Delegattyp 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>. Ein Lambda-Ausdruck ist die einfachste Möglichkeit zum Erstellen dieses Delegaten.A lambda expression is the most convenient way to create that delegate. Wenn Sie dieselbe Methode z.B. in der System.Linq.Queryable-Klasse aufrufen (wie in LINQ to SQLLINQ to SQL), handelt es sich bei dem Parametertyp um eine System.Linq.Expressions.Expression<Funktion>, wobei „Funktion“ für beliebige Funktionsdelegaten mit bis zu 16 Eingabeparametern steht.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. Wie gesagt, ein Lambda-Ausdruck ist eine sehr präzise Methode, diese Ausdrucksbaumstruktur zu erstellen.Again, a lambda expression is just a very concise way to construct that expression tree. Durch die Lambdas können die Where -Aufrufe ähnlich aussehen, obwohl sich der mithilfe des Lambdas erstellte Objekttyp unterscheidet.The lambdas allow the Where calls to look similar although in fact the type of object created from the lambda is different.

Beachten Sie im vorigen Beispiel, dass die Signatur des Delegaten über einen implizit typisierten Eingabeparameter vom Typ intverfügt und intzurückgibt.In the previous example, notice that the delegate signature has one implicitly-typed input parameter of type int, and returns an int. Der Lambda-Ausdruck kann in einen Delegaten dieses Typs konvertiert werden, da er auch über einen Eingabeparameter (x) und einen Rückgabewert verfügt, der vom Compiler implizit in den Typ int konvertiert werden kann.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. (Der Typrückschluss wird in den folgenden Abschnitten ausführlicher erläutert.) Wenn der Delegat durch Verwendung des Eingabeparameters 5 aufgerufen wird, wird als Ergebnis 25 zurückgegeben.(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.

Lambdas sind auf der linken Seite des Operators is oder as nicht zugelassen.Lambdas are not allowed on the left side of the is or as operator.

Alle Einschränkungen für anonyme Methoden gelten auch für Lambda-Ausdrücke.All restrictions that apply to anonymous methods also apply to lambda expressions. Weitere Informationen finden Sie unter Anonyme Methoden.For more information, see Anonymous Methods.

AusdruckslambdasExpression Lambdas

Ein Lambdaausdruck mit einem Ausdruck auf der rechten Seite des Operators „=>“ wird als Ausdruckslambda bezeichnet.A lambda expression with an expression on the right side of the => operator is called an expression lambda. Ausdruckslambdas werden häufig bei der Erstellung von Ausdrucksbaumstrukturenverwendet.Expression lambdas are used extensively in the construction of Expression Trees. Ein Ausdruckslambda gibt das Ergebnis des Ausdrucks zurück und hat folgende grundlegende Form:An expression lambda returns the result of the expression and takes the following basic form:

(input-parameters) => expression

Die Klammern sind nur optional, wenn das Lambda über einen Eingabeparameter verfügt; andernfalls sind sie erforderlich.The parentheses are optional only if the lambda has one input parameter; otherwise they are required. Zwei oder mehr Eingabeparameter sind durch Kommas getrennt und in Klammern eingeschlossen:Two or more input parameters are separated by commas enclosed in parentheses:

(x, y) => x == y

Für den Compiler kann es schwierig oder unmöglich sein, die Eingabetypen abzuleiten.Sometimes it is difficult or impossible for the compiler to infer the input types. Wenn dieses Problem auftritt, können Sie die Typen explizit angeben, wie im folgenden Beispiel dargestellt:When this occurs, you can specify the types explicitly as shown in the following example:

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

Geben Sie Eingabeparameter von 0 (null) mit leeren Klammern an:Specify zero input parameters with empty parentheses:

() => SomeMethod()

Beachten Sie im vorherigen Beispiel, dass der Text eines Ausdruckslambdas ein Methodenaufruf sein kann.Note in the previous example that the body of an expression lambda can consist of a method call. Wenn Sie jedoch Ausdrucksbaumstrukturen erstellen, die auf einer anderen Plattform als .NET Framework ausgewertet werden, z. B. SQL Server, sollten Sie in Lambda-Ausdrücken keine Methodenaufrufe verwenden.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. Die Methoden haben außerhalb des Kontexts der .NET Common Language Runtime keine Bedeutung.The methods will have no meaning outside the context of the .NET common language runtime.

AnweisungslambdasStatement Lambdas

Ein Anweisungslambda ähnelt einem Ausdruckslambda, allerdings sind die Anweisungen in Klammern eingeschlossen:A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:

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

Der Text eines Anweisungslambdas kann aus einer beliebigen Anzahl von Anweisungen bestehen, wobei es sich meistens um höchstens zwei oder drei Anweisungen handelt.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); };

Anweisungslambdas, wie anonyme Methoden, können nicht zum Erstellen von Ausdrucksbaumstrukturen verwendet werden.Statement lambdas, like anonymous methods, cannot be used to create expression trees.

Asynchrone LambdasAsync Lambdas

Sie können mit den Schlüsselwörtern async und await Lambda-Ausdrücke und Anweisungen, die asynchrone Verarbeitung enthalten, leicht erstellen.You can easily create lambda expressions and statements that incorporate asynchronous processing by using the async and await keywords. Das folgende Windows Forms enthält z. B. einen Ereignishandler, der eine Async-Methode, ExampleMethodAsync, aufruft und erwartet.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);  
    }  
}  

Sie können denselben Ereignishandler hinzufügen, indem Sie ein asynchrones Lambda verwenden.You can add the same event handler by using an async lambda. Um diesen Handler hinzuzufügen, fügen Sie einen async -Modifizierer vor der Lambda-Parameterliste, wie im folgenden Beispiel dargestellt, hinzu.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);  
    }  
}  

Weitere Informationen zum Erstellen und Verwenden von asynchronen Methoden finden Sie unter Asynchronous programming with async and await (Asynchrones Programmieren mit „async“ and „await“).For more information about how to create and use async methods, see Asynchronous Programming with async and await.

Lambdas mit StandardabfrageoperatorenLambdas with the Standard Query Operators

Viele Standardabfrageoperatoren weisen einen Eingabeparameter auf, deren Typ einem der Typen aus der Func<T,TResult> -Familie generischer Delegaten entspricht.Many Standard query operators have an input parameter whose type is one of the Func<T,TResult> family of generic delegates. Diese Delegaten verwenden Typparameter zur Definition der Anzahl und des Typs der Eingabeparameter sowie des Rückgabetyps des Delegaten.These delegates use type parameters to define the number and types of input parameters, and the return type of the delegate. Func -Delegaten sind für das Kapseln von benutzerdefinierten Ausdrücken, die für jedes Element in einem Satz von Quelldaten übernommen werden, sehr nützlich.Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. Betrachten Sie z. B. den folgenden Delegattyp:For example, consider the following delegate type:

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

Der Delegat kann als Func<int,bool> myFunc instanziiert werden, wobei int ein Eingabeparameter und bool der Rückgabewert ist.The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. Der Rückgabewert wird immer im letzten Typparameter angegeben.The return value is always specified in the last type parameter. Func<int, string, bool> definiert einen Delegaten mit zwei Eingabeparametern, int und string, und einen Rückgabetyp von bool.Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. Der folgende Func -Delegat gibt bei einem Aufruf true oder false zurück, um anzugeben, ob der Eingabeparameter gleich 5 ist: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  

Sie können einen Lambda-Ausdruck auch dann angeben, wenn der Argumenttyp Expression<Func>ist, beispielsweise in den Standardabfrageoperatoren, die in System.Linq.Queryable definiert sind.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. Wenn Sie ein Expression<Func> -Argument angeben, wird der Lambda-Ausdruck in eine Ausdrucksbaumstruktur kompiliert.When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.

Hier wird ein Standardabfrageoperator, die Count -Methode, angezeigt: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);  

Der Compiler kann den Typ des Eingabeparameters ableiten, Sie können ihn aber auch explizit angeben.The compiler can infer the type of the input parameter, or you can also specify it explicitly. Dieser bestimmte Lambda-Ausdruck zählt die ganzen Zahlen (n), bei denen nach dem Dividieren durch zwei als Rest 1 bleibt.This particular lambda expression counts those integers (n) which when divided by two have a remainder of 1.

Mit der folgenden Codezeile wird eine Sequenz erzeugt, die alle Elemente im numbers -Array enthält, die vor der 9 auftreten, da dies die erste Zahl in der Sequenz ist, die die Bedingung nicht erfüllt: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);  

In diesem Beispiel wird gezeigt, wie Sie mehrere Eingabeparameter angeben, indem Sie sie in Klammern einschließen.This example shows how to specify multiple input parameters by enclosing them in parentheses. Mit der Methode werden alle Elemente im Zahlenarray zurückgegeben, bis eine Zahl erreicht wird, deren Wert kleiner ist als seine Position.The method returns all the elements in the numbers array until a number is encountered whose value is less than its position. Verwechseln Sie den Lambda-Operator (=>) nicht mit dem Operator "Größer als oder gleich" (>=).Do not confuse the lambda operator (=>) with the greater than or equal operator (>=).

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

Typrückschluss in LambdasType Inference in Lambdas

Beim Schreiben von Lambdas müssen Sie oftmals keinen Typ für die Eingabeparameter angeben, da der Compiler den Typ auf der Grundlage des Lambda-Texts, des zugrunde liegenden Delegattyps des Parameters und anderer Faktoren per Rückschluss ableiten kann, wie in der C#-Programmiersprachenspezifikation beschrieben.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. Bei den meisten Standardabfrageoperatoren entspricht die erste Eingabe dem Typ der Elemente in der Quellsequenz.For most of the standard query operators, the first input is the type of the elements in the source sequence. Beim Abfragen von IEnumerable<Customer>wird die Eingabevariable als Customer -Objekt abgeleitet, sodass Sie auf die zugehörigen Methoden und Eigenschaften zugreifen können: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");  

Die allgemeinen Regeln für Lambdas lauten wie folgt:The general rules for lambdas are as follows:

  • Der Lambda-Ausdruck muss dieselbe Anzahl von Parametern enthalten wie der Delegattyp.The lambda must contain the same number of parameters as the delegate type.

  • Jeder Eingabeparameter im Lambda muss implizit in den entsprechenden Delegatparameter konvertiert werden können.Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.

  • Der Rückgabewert des Lambdas (falls vorhanden) muss implizit in den Rückgabetyp des Delegaten konvertiert werden können.The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.

Beachten Sie, dass Lambda-Ausdrücke keinen eigenen Typ haben, da das allgemeine Typsystem kein internes Konzept von "Lambda-Ausdrücken" aufweist.Note that lambda expressions in themselves do not have a type because the common type system has no intrinsic concept of "lambda expression." Es kann manchmal praktisch sein, informell vom "Typ" eines Lambda-Ausdrucks zu sprechen.However, it is sometimes convenient to speak informally of the "type" of a lambda expression. In einem solchen Fall bezeichnet Typ den Delegattyp bzw. den Expression -Typ, in den der Lambda-Ausdruck konvertiert wird.In these cases the type refers to the delegate type or Expression type to which the lambda expression is converted.

Variablenbereich in Lambda-AusdrückenVariable Scope in Lambda Expressions

Lambdas können auf äußere Variablen verweisen (siehe Anonyme Methoden), die im Bereich der Methode, mit der die Lambdafunktion definiert wird, oder im Bereich des Typs liegen, der den Lambdaausdruck enthält.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. Variablen, die auf diese Weise erfasst werden, werden zur Verwendung in Lambda-Ausdrücken gespeichert, auch wenn die Variablen andernfalls außerhalb des Gültigkeitsbereichs liegen und an die Garbage Collection übergeben würden.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. Eine äußere Variable muss definitiv zugewiesen sein, bevor sie in einem Lambda-Ausdruck verwendet werden kann.An outer variable must be definitely assigned before it can be consumed in a lambda expression. Das folgende Beispiel veranschaulicht diese Regeln: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();  
    }  
}  

Die folgenden Regeln gelten für den Variablenbereich in Lambda-Ausdrücken:The following rules apply to variable scope in lambda expressions:

  • Eine erfasste Variable wird erst dann an die Garbage Collection übergeben, wenn der darauf verweisende Delegat für die Garbage Collection geeignet ist.A variable that is captured will not be garbage-collected until the delegate that references it becomes eligible for garbage collection.

  • Variablen, die in einem Lambda-Ausdruck eingeführt wurden, sind in der äußeren Methode nicht sichtbar.Variables introduced within a lambda expression are not visible in the outer method.

  • Ein Lambda-Ausdruck kann einen ref - oder out -Parameter nicht direkt von einer einschließenden Methode erfassen.A lambda expression cannot directly capture a ref or out parameter from an enclosing method.

  • Eine return-Anweisung in einem Lambda-Ausdruck bewirkt keine Rückgabe durch die einschließende Methode.A return statement in a lambda expression does not cause the enclosing method to return.

  • Ein Lambda-Ausdruck kann eine goto -Anweisung, break -Anweisung oder continue -Anweisung enthalten, die innerhalb der Lambda-Funktion liegt, wenn das Ziel der jump-Anweisung außerhalb des Blocks liegt.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. Eine jump-Anweisung darf auch nicht außerhalb des Lambda-Funktionsblocks sein, wenn das Ziel im Block ist.It is also an error to have a jump statement outside the lambda function block if the target is inside the block.

C#-ProgrammiersprachenspezifikationC# Language Specification

Weitere Informationen erhalten Sie unter C#-Sprachspezifikation. Die Sprachspezifikation ist die verbindliche Quelle für die Syntax und Verwendung von C#.

Delegaten, Ereignisse und Lambda-Ausdrücke im C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmersDelegates, Events, and Lambda Expressions in C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers

Siehe auchSee Also

C#-ProgrammierhandbuchC# Programming Guide
LINQ (Language Integrated Query)LINQ (Language-Integrated Query)
Anonyme MethodenAnonymous Methods
isis
AusdrucksbaumstrukturenExpression Trees
Visual Studio 2008 C#-Beispiele (Siehe LINQ Beispielabfragedateien und XQuery-Programm)Visual Studio 2008 C# Samples (see LINQ Sample Queries files and XQuery program)
Rekursive Lambda-AusdrückeRecursive lambda expressions