Wyrażenia lambda (Przewodnik programowania w języku C#)Lambda Expressions (C# Programming Guide)

Wyrażenie lambda jest funkcji anonimowej używanej do tworzenia delegaty lub drzewo wyrażeń typów.A lambda expression is an anonymous function that you can use to create delegates or expression tree types. Za pomocą wyrażenia lambda można pisać funkcje lokalne, które mogą być przekazywane jako argumenty lub zwracane jako wartość wywołania funkcji.By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls. Wyrażenia lambda są szczególnie przydatne w przypadku pisania wyrażeń zapytań w języku LINQ.Lambda expressions are particularly helpful for writing LINQ query expressions.

Aby utworzyć wyrażenie lambda, należy określić parametry wejściowe (jeśli istnieją) po lewej stronie operatora lambda => , i umieszcza blok wyrażenia lub instrukcji z drugiej strony.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. Na przykład, wyrażenie lambda x => x * x określa parametr o nazwie x i zwraca wartość x kwadratów.For example, the lambda expression x => x * x specifies a parameter that’s named x and returns the value of x squared. To wyrażenie można przypisać do typu delegata, tak jak pokazano w poniższym przykładzie: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  
}  

Aby utworzyć typ drzewa wyrażeń: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;  
        }  
    }  
}  

=> Operator ma takie samo pierwszeństwo jako przypisania (=) i jest prawo asocjacyjnej (zobacz sekcję "Kojarzenie" w artykule operatory).The => operator has the same precedence as assignment (=) and is right associative (see "Associativity" section of the Operators article).

Wyrażenia lambda są używane w oparte na metodzie LINQLINQ wysyła zapytanie jako argumenty do metod operator standardowej kwerendy, takich jak Where.Lambdas are used in method-based LINQLINQ queries as arguments to standard query operator methods such as Where.

Jeśli używasz składni na podstawie metody do wywołania Where metody w Enumerable klasy (tak jak w LINQLINQ do obiektów i LINQ do XMLLINQ to XML) parametr jest typem obiektu delegowanego 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 do XMLLINQ to XML) the parameter is a delegate type System.Func<T,TResult>. Użycie wyrażenia lambda jest najwygodniejszym sposobem tworzenia delegata.A lambda expression is the most convenient way to create that delegate. Podczas wywoływania tej samej metody, na przykład System.Linq.Queryable klasy (tak jak w LINQ do SQLLINQ to SQL), a następnie typ parametru jest System.Linq.Expressions.Expression< Func> Func w przypadku dowolnego delegatów Func o do szesnastu parametrów wejściowych.When you call the same method in, for example, the System.Linq.Queryable class (as you do in LINQ do 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. I znowu wyrażenie lambda jest tylko bardzo zwięzłym sposobem konstruowania takiego drzewa wyrażeń.Again, a lambda expression is just a very concise way to construct that expression tree. Zezwalaj na wyrażeń lambda Where wywołań wyglądać podobnie, chociaż w rzeczywistości różni się typ obiektu utworzone na podstawie lambda.The lambdas allow the Where calls to look similar although in fact the type of object created from the lambda is different.

W poprzednim przykładzie parametr typu wejściowy powiadomienie, że podpis delegata ma jedną niejawnie wpisanych inti zwraca int.In the previous example, notice that the delegate signature has one implicitly-typed input parameter of type int, and returns an int. Wyrażenia lambda można przekonwertować na delegata tego typu, ponieważ obejmuje ona również jeden parametr wejściowy (x) i które kompilator niejawnie przekonwertować na typ wartości zwracanej 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. (Wnioskowanie typów omówiono bardziej szczegółowo w następnych sekcjach). Kiedy delegat jest wywołany za pomocą parametru wejściowego 5, zwraca wynik 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.

Wyrażenia lambda nie są dozwolone w lewej części jest lub jako operatora.Lambdas are not allowed on the left side of the is or as operator.

Wszystkie ograniczenia, które dotyczą metod anonimowych, dotyczą także wyrażeń lambda.All restrictions that apply to anonymous methods also apply to lambda expressions. Aby uzyskać więcej informacji, zobacz metod anonimowych.For more information, see Anonymous Methods.

Lambdy wyrażeńExpression Lambdas

Wyrażenia lambda za pomocą wyrażenia po prawej stronie = > — operator jest wywoływana wyrażenia lambda.A lambda expression with an expression on the right side of the => operator is called an expression lambda. Wyrażenia lambda są często używane w konstrukcji drzew wyrażeń.Expression lambdas are used extensively in the construction of Expression Trees. Lambda wyrażenia zwraca wynik wyrażenia i ma następującą podstawową formę:An expression lambda returns the result of the expression and takes the following basic form:

(input-parameters) => expression

Nawiasy są opcjonalne tylko wtedy, gdy lambda ma jeden parametr wejściowy; w przeciwnym razie są wymagane.The parentheses are optional only if the lambda has one input parameter; otherwise they are required. Jeśli liczba parametrów wejściowych wynosi dwa lub więcej, te parametry są rozdzielane przecinkami i umieszczone w nawiasach:Two or more input parameters are separated by commas enclosed in parentheses:

(x, y) => x == y

Czasami wywnioskowanie typów wejściowych jest dla kompilatora trudne lub wręcz niemożliwe.Sometimes it is difficult or impossible for the compiler to infer the input types. W takiej sytuacji można jawnie określić typy, tak jak pokazano w poniższym przykładzie:When this occurs, you can specify the types explicitly as shown in the following example:

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

Określanie braku parametrów wejściowych za pomocą pustych nawiasów:Specify zero input parameters with empty parentheses:

() => SomeMethod()

Należy zauważyć, że w poprzednim przykładzie treść wyrażenia lambda może składać się z wywołania metody.Note in the previous example that the body of an expression lambda can consist of a method call. Jednak w przypadku tworzenia drzew wyrażeń, które będą obliczane poza programem .NET Framework, na przykład w programie SQL Server, nie należy używać wywołań metod w wyrażeniach lambda.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. Te metody nie będą zrozumiałe poza kontekstem środowiska uruchomieniowego języka wspólnego platformy .NET.The methods will have no meaning outside the context of the .NET common language runtime.

Lambdy instrukcjiStatement Lambdas

Lambda instrukcji jest podobna do lambdy wyrażenia, z tym że instrukcje są ujęte w nawiasy klamrowe:A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:

(parametry wejściowe) = > {instrukcja;}(input-parameters) => { statement; }

Treść lambdy instrukcji może składać się z dowolnej liczby instrukcji, jednak w praktyce jest ich zwykle nie więcej niż dwie lub trzy.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); };

Lambd instrukcji, podobnie jak metod anonimowych, nie można używać do tworzenia drzew wyrażeń.Statement lambdas, like anonymous methods, cannot be used to create expression trees.

Lambdy asynchroniczneAsync Lambdas

Można jednak łatwo tworzyć wyrażenia lambda i instrukcje zawierające przetwarzania asynchronicznego przy użyciu async i await słów kluczowych.You can easily create lambda expressions and statements that incorporate asynchronous processing by using the async and await keywords. Na przykład w poniższym przykładzie formularzy systemu Windows zawiera program obsługi zdarzeń, który wywołuje i oczekujące na metody asynchronicznej 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);  
    }  
}  

Można dodać ten sam program obsługi zdarzeń, używając lambdy asynchronicznej.You can add the same event handler by using an async lambda. Aby dodać ten program obsługi, Dodaj async modyfikator przed listy parametrów lambda, jak przedstawiono na poniższym przykładzie.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);  
    }  
}  

Aby uzyskać więcej informacji o sposobie tworzenia i używania metody asynchroniczne, zobacz programowanie asynchroniczne z async i await.For more information about how to create and use async methods, see Asynchronous Programming with async and await.

Lambdy ze standardowymi operatorami zapytańLambdas with the Standard Query Operators

Wiele standardowych operatorów zapytań ma parametr wejściowy, którego typ jest jednym z Func<T,TResult> rodzina delegatów.Many Standard query operators have an input parameter whose type is one of the Func<T,TResult> family of generic delegates. Te delegaty używają parametrów typu użycia, aby zdefiniować liczbę i typy parametrów wejściowych oraz zwracany typ delegata.These delegates use type parameters to define the number and types of input parameters, and the return type of the delegate. Func Obiekty delegowane są bardzo przydatne w przypadku hermetyzując wyrażenia zdefiniowane przez użytkownika, które są stosowane do każdego elementu w zestawie danych źródłowych.Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. Na przykład rozważmy następujący typ delegata:For example, consider the following delegate type:

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

Delegat można wdrożyć jako Func<int,bool> myFunc gdzie int jest parametrem wejściowym i bool jest zwracana wartość.The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. Wartość zwracana jest zawsze określona w ostatnim parametrze typu.The return value is always specified in the last type parameter. Func<int, string, bool> Definiuje delegata z dwóch parametrów wejściowych, int i stringi typ zwracany bool.Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. Następujące Func delegata, gdy jest wywoływana, zwraca wartość PRAWDA lub FAŁSZ, aby wskazać, czy parametr wejściowy jest równa 5: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  

Może też podawać wyrażenia lambda, gdy typ argumentu jest Expression<Func>, na przykład w przypadku standardowych operatorów zapytań zdefiniowane w System.Linq.Queryable.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. Po określeniu Expression<Func> argument, wyrażenie lambda zostanie skompilowany na drzewo wyrażenia.When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.

Operator zapytania standardowe Count metody, jest następujący: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);  

Kompilator może wywnioskować typ parametru wejściowego, ale można go również określić w sposób jawny.The compiler can infer the type of the input parameter, or you can also specify it explicitly. To wyrażenie lambda określonej liczby tych liczb całkowitych (n) który podzielona przez dwa mieć reszty 1.This particular lambda expression counts those integers (n) which when divided by two have a remainder of 1.

Następujący wiersz kodu tworzy sekwencję, który zawiera wszystkie elementy w numbers tablicy, które są do lewej strony 9, ponieważ jest to pierwszy numer w sekwencji, które nie spełniają warunek: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);  

W tym przykładzie pokazano, jak określić wiele parametrów danych wejściowych, umieszczając je w nawiasach.This example shows how to specify multiple input parameters by enclosing them in parentheses. Metoda zwraca wszystkie elementy w tablicy liczb, dopóki nie napotka liczby, której wartość jest mniejsza niż jej pozycja.The method returns all the elements in the numbers array until a number is encountered whose value is less than its position. Nie należy mylić operatora lambda (=>) z operatorem większe lub równe (>=).Do not confuse the lambda operator (=>) with the greater than or equal operator (>=).

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

Wnioskowanie typów w wyrażeniach lambdaType Inference in Lambdas

Podczas pisania wyrażeń lambda często nie trzeba określać typu parametrów wejściowych, ponieważ kompilator może wywnioskować typ na podstawie treści wyrażenia lambda, typu delegata parametru i innych czynników, tak jak opisano w specyfikacji języka 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. Dla większości standardowych operatorów zapytań pierwszy element danych wejściowych jest typem elementów w sekwencji źródłowej.For most of the standard query operators, the first input is the type of the elements in the source sequence. Tak, wyszukując IEnumerable<Customer>, następnie wejściowego zmiennej jest wywnioskowany jako Customer obiektu, co oznacza, że masz dostęp do właściwości i metod: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");  

Ogólne reguły dotyczące wyrażeń lambda są następujące:The general rules for lambdas are as follows:

  • Wyrażenie lambda musi zawierać taką samą liczbę parametrów jak typ delegata.The lambda must contain the same number of parameters as the delegate type.

  • Każdy parametr wejściowy w wyrażeniu lambda musi umożliwiać niejawną konwersję na odpowiadający mu parametr delegata.Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.

  • Wartość zwracana wyrażenia lambda (jeżeli istnieje) musi umożliwiać niejawną konwersję na zwracany typ delegata.The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.

Należy zauważyć, że wyrażenia lambda same w sobie nie mają typu, ponieważ system typów wspólnych nie obejmuje wewnętrznej koncepcji „wyrażenia lambda”.Note that lambda expressions in themselves do not have a type because the common type system has no intrinsic concept of "lambda expression." Jednak czasami wygodnie jest mówić potocznie o „typie” wyrażenia lambda.However, it is sometimes convenient to speak informally of the "type" of a lambda expression. W takich przypadkach typ odwołuje się do typu delegata lub Expression wpisz jest konwertowane Wyrażenie lambda.In these cases the type refers to the delegate type or Expression type to which the lambda expression is converted.

Zakres zmiennych w wyrażeniach lambdaVariable Scope in Lambda Expressions

Wyrażenia lambda, może się odwoływać do zmienne zewnętrzne (zobacz metod anonimowych) w zakresie w metodę, która definiuje funkcję lambda, lub w zakresie w typie, który zawiera wyrażenie lambda.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. Przechwytywane w ten sposób zmienne są przechowywane do użytku w wyrażeniu lambda, nawet gdyby w innym wypadku te zmienne znalazłyby się poza zakresem i zostałyby usunięte w ramach odśmiecania pamięci.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. Zewnętrzna zmienna musi być zdecydowanie przypisana, aby można jej było użyć w wyrażeniu lambda.An outer variable must be definitely assigned before it can be consumed in a lambda expression. W poniższym przykładzie pokazano te reguły: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();  
    }  
}  

Do zakresu zmiennych w wyrażeniach lambda są stosowane następujące reguły:The following rules apply to variable scope in lambda expressions:

  • Zmienna, która jest przechwytywana, nie będzie usuwana w ramach odśmiecania pamięci, dopóki odwołujący się do niej delegat nie będzie podlegał odśmiecaniu pamięci.A variable that is captured will not be garbage-collected until the delegate that references it becomes eligible for garbage collection.

  • Zmienne zawarte w wyrażeniu lambda nie są widoczne w metodzie zewnętrznej.Variables introduced within a lambda expression are not visible in the outer method.

  • Wyrażenia lambda nie może bezpośrednio przechwytywania in, ref, lub out parametru z metody otaczającej.A lambda expression cannot directly capture an in, ref, or out parameter from an enclosing method.

  • Instrukcja return w wyrażeniu lambda nie powoduje wykonania instrukcji return w otaczającej go metodzie.A return statement in a lambda expression does not cause the enclosing method to return.

  • Wyrażenia lambda nie może zawierać goto instrukcji, break instrukcji lub continue instrukcji, która znajduje się wewnątrz funkcji lambda w przypadku docelowej instrukcji skok poza blokiem.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. Błędem jest również instrukcja skoku poza blok funkcji lambda, jeśli obiekt docelowy znajduje się wewnątrz bloku.It is also an error to have a jump statement outside the lambda function block if the target is inside the block.

Specyfikacja języka C#C# Language Specification

Aby uzyskać więcej informacji, zobacz Specyfikacja języka C#.For more information, see the C# Language Specification. Specyfikacja języka jest ostatecznym źródłem informacji o składni i użyciu języka C#.The language specification is the definitive source for C# syntax and usage.

Obiekty delegowane, zdarzeń i wyrażenia Lambda w C# 3.0 Cookbook, trzecia edycja: ponad 250 rozwiązań dla programistów języka C# 3.0Delegates, Events, and Lambda Expressions in C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers

Zobacz teżSee Also

Przewodnik programowania w języku C#C# Programming Guide
LINQ (zapytania o języku zintegrowanym)LINQ (Language-Integrated Query)
Metody anonimoweAnonymous Methods
isis
Drzewa wyrażeńExpression Trees
Visual Studio 2008 C# przykłady (zobacz zapytań LINQ przykładowe pliki i XQuery program)Visual Studio 2008 C# Samples (see LINQ Sample Queries files and XQuery program)
Wyrażenia lambda cykliczneRecursive lambda expressions