Espressioni lambda (Guida per programmatori C#)Lambda Expressions (C# Programming Guide)

Un'espressione lambda è una funzione anonima che è possibile utilizzare per creare delegati o tipi di alberi delle espressioni .A lambda expression is an anonymous function that you can use to create delegates or expression tree types. Mediante le espressioni lambda è possibile scrivere funzioni locali che possono essere passate come argomenti o restituite come valore delle chiamate di funzione.By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls. Le espressioni lambda sono particolarmente utili per la scrittura delle espressioni di query LINQ.Lambda expressions are particularly helpful for writing LINQ query expressions.

Per creare un'espressione lambda, specificare gli eventuali parametri di input a sinistra dell'operatore lambda =>e inserire l'espressione o il blocco di istruzioni dall'altra parte.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. Ad esempio, l'espressione lambda x => x * x specifica un parametro denominato x e restituisce il valore di x al quadrato.For example, the lambda expression x => x * x specifies a parameter that’s named x and returns the value of x squared. È possibile assegnare questa espressione a un tipo di delegato, come illustrato nell'esempio riportato di seguito: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  
}  

Per creare un tipo di albero delle espressioni: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;  
        }  
    }  
}  

L'operatore => ha la stessa precedenza dell'assegnazione (=) e prevede l'associazione all'operando di destra (vedere la sezione "Associazione" dell'articolo sugli operatori).The => operator has the same precedence as assignment (=) and is right associative (see "Associativity" section of the Operators article).

Le espressioni lambda vengono utilizzate nelle query LINQLINQ basate sul metodo come argomenti dei metodi di operatori di query standard, quali Where.Lambdas are used in method-based LINQLINQ queries as arguments to standard query operator methods such as Where.

Quando si utilizza la sintassi basata sul metodo per chiamare il metodo Where nella classe Enumerable , come in LINQLINQ to Objects e LINQ to XMLLINQ to XML, il parametro è un tipo System.Func<T,TResult>delegato.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 XMLLINQ to XML) the parameter is a delegate type System.Func<T,TResult>. Un'espressione lambda è il modo più pratico per creare tale delegato.A lambda expression is the most convenient way to create that delegate. Quando, ad esempio, si chiama lo stesso metodo nella classe System.Linq.Queryable, come in LINQ to SQLLINQ to SQL, il tipo di parametro è System.Linq.Expressions.Expression<Func>, dove Func è un qualsiasi delegato Func con un massimo di sedici parametri di input.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. Un'espressione lambda rappresenta quindi un modo rapido per costruire tale albero delle espressioni.Again, a lambda expression is just a very concise way to construct that expression tree. Mediante le espressioni lambda, le chiamate Where risultano simili anche se in realtà il tipo di oggetto creato dall'espressione lambda è diverso.The lambdas allow the Where calls to look similar although in fact the type of object created from the lambda is different.

Nell'esempio precedente si noti che la firma del delegato ha un parametro di input tipizzato in modo implicito di tipo inte restituisce un oggetto int.In the previous example, notice that the delegate signature has one implicitly-typed input parameter of type int, and returns an int. L'espressione lambda può essere convertita in un delegato di tale tipo poiché dispone anche di un parametro di input (x) e di un valore restituito che il compilatore può convertire in modo implicito nel tipo 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. L'inferenza dei tipi viene illustrata più dettagliatamente nelle sezioni seguenti. Quando il delegato viene richiamato tramite un parametro di input pari a 5, restituisce un risultato di 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.

Non è possibile usare le espressioni lambda a sinistra dell'operatore is o as.Lambdas are not allowed on the left side of the is or as operator.

Tutte le restrizioni che si applicano ai metodi anonimi si applicano anche alle espressioni lambda.All restrictions that apply to anonymous methods also apply to lambda expressions. Per altre informazioni, vedere Metodi anonimi.For more information, see Anonymous Methods.

Espressioni lambdaExpression Lambdas

Un'espressione lambda con un'espressione a destra dell'operatore => è denominata espressione lambda.A lambda expression with an expression on the right side of the => operator is called an expression lambda. Queste espressioni vengono usate spesso nella costruzione di alberi delle espressioni.Expression lambdas are used extensively in the construction of Expression Trees. Un'espressione lambda dell'espressione restituisce il risultato dell'espressione e ha il formato di base seguente:An expression lambda returns the result of the expression and takes the following basic form:

(input-parameters) => expression

Le parentesi sono facoltative solo se l'espressione lambda ha un parametro di input; in caso contrario sono obbligatorie.The parentheses are optional only if the lambda has one input parameter; otherwise they are required. Due o più parametri di input vengono separati da virgole e racchiusi tra parentesi:Two or more input parameters are separated by commas enclosed in parentheses:

(x, y) => x == y

Talvolta è difficile o impossibile che il compilatore deduca i tipi di input.Sometimes it is difficult or impossible for the compiler to infer the input types. In tal caso, è possibile specificare i tipi in modo esplicito come illustrato nell'esempio seguente:When this occurs, you can specify the types explicitly as shown in the following example:

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

Specificare zero parametri di input con parentesi vuote:Specify zero input parameters with empty parentheses:

() => SomeMethod()

Si noti che nell'esempio precedente il corpo di un'espressione lambda dell'espressione può essere costituito da una chiamata al metodo.Note in the previous example that the body of an expression lambda can consist of a method call. Tuttavia, se si creano alberi delle espressioni valutati al di fuori di .NET Framework, ad esempio in SQL Server, non è consigliabile utilizzare chiamate al metodo nelle espressioni 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. I metodi non avranno alcun significato all'esterno del contesto di .NET Common Language Runtime.The methods will have no meaning outside the context of the .NET common language runtime.

Espressioni lambda dell'istruzioneStatement Lambdas

Un'espressione lambda dell'istruzione è simile a un'espressione lambda dell'espressione con la differenza che l'istruzione o le istruzioni sono racchiuse tra parentesi graffe:A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:

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

Il corpo di un'espressione lambda dell'istruzione può essere costituito da un numero qualsiasi di istruzioni, sebbene in pratica generalmente non ce ne siano più di due o tre.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); };

Le espressioni lambda dell'istruzione, come i metodi anonimi, non possono essere utilizzate per creare alberi delle espressioni.Statement lambdas, like anonymous methods, cannot be used to create expression trees.

Espressioni lambda asincroneAsync Lambdas

È facile creare istruzioni ed espressioni lambda che includono l'elaborazione asincrona utilizzando le parole chiave async e await .You can easily create lambda expressions and statements that incorporate asynchronous processing by using the async and await keywords. Nell'esempio seguente di Windows Form è presente un gestore eventi che chiama e attende un metodo asincrono, 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);  
    }  
}  

È possibile aggiungere lo stesso gestore eventi utilizzando un'espressione lambda asincrona.You can add the same event handler by using an async lambda. Per aggiungere il gestore, aggiungere un modificatore async prima dell'elenco di parametri lambda, come illustrato di seguito.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);  
    }  
}  

Per altre informazioni su come creare e usare i metodi asincroni, vedere Programmazione asincrona con async e await.For more information about how to create and use async methods, see Asynchronous Programming with async and await.

Espressioni lambda con operatori di query standardLambdas with the Standard Query Operators

Molti operatori di query standard hanno un parametro di input il cui tipo è uno della famiglia Func<T,TResult> di delegati generici.Many Standard query operators have an input parameter whose type is one of the Func<T,TResult> family of generic delegates. Questi delegati utilizzano parametri di tipo per definire il numero e i tipi di parametri di input e il tipo restituito del delegato.These delegates use type parameters to define the number and types of input parameters, and the return type of the delegate. I delegatiFunc sono molto utili per incapsulare le espressioni definite dall'utente applicate a ogni elemento in un set di dati di origine.Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. Considerare ad esempio il seguente tipo delegato:For example, consider the following delegate type:

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

È possibile creare un'istanza del delegato come Func<int,bool> myFunc dove int è un parametro di input e bool è il valore restituito.The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. Il valore restituito è sempre specificato nell'ultimo parametro di tipo.The return value is always specified in the last type parameter. Func<int, string, bool> definisce un delegato con due parametri di input, int e string, e un tipo restituito bool.Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. Quando viene richiamato, il delegato Func seguente restituisce true o false per indicare se il parametro di input è uguale a 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  

È inoltre possibile fornire un'espressione lambda quando il tipo di argomento è Expression<Func>, ad esempio negli operatori di query standard definiti in 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. Quando si specifica un argomento Expression<Func> , l'espressione lambda viene compilata in un albero delle espressioni.When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.

Di seguito viene illustrato un operatore di query standard, il metodo 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);  

Il compilatore è in grado di dedurre il tipo del parametro di input oppure è possibile specificarlo in modo esplicito.The compiler can infer the type of the input parameter, or you can also specify it explicitly. Questa espressione lambda particolare conta i numeri interi (n) che divisi per due danno il resto di 1.This particular lambda expression counts those integers (n) which when divided by two have a remainder of 1.

La seguente riga di codice produce una sequenza che contiene tutti gli elementi presenti nella matrice numbers che si trovano a sinistra di 9, che rappresenta il primo numero della sequenza che non soddisfa la condizione: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 questo esempio viene illustrato come specificare più parametri di input racchiudendoli tra parentesi.This example shows how to specify multiple input parameters by enclosing them in parentheses. Il metodo restituisce tutti gli elementi presenti nella matrice di numeri finché non viene rilevato un numero il cui valore è inferiore alla relativa posizione.The method returns all the elements in the numbers array until a number is encountered whose value is less than its position. Non confondere l'operatore lambda (=>) con l'operatore Greater Than o Equals (>=).Do not confuse the lambda operator (=>) with the greater than or equal operator (>=).

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

Inferenza dei tipi nelle espressioni lambdaType Inference in Lambdas

Quando si scrivono le espressioni lambda, spesso non occorre specificare un tipo per i parametri di input in quanto il compilatore è in grado di dedurlo in base al corpo dell'espressione lambda, al tipo delegato del parametro e ad altri fattori, come descritto nella specifica del linguaggio 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. Per la maggior parte degli operatori di query standard, il primo input è il tipo degli elementi nella sequenza di origine.For most of the standard query operators, the first input is the type of the elements in the source sequence. Pertanto se si esegue una query su un oggetto IEnumerable<Customer>, si deduce che la variabile di input sia un oggetto Customer , ovvero che si dispone dell'accesso ai relativi metodi e proprietà: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");  

Di seguito sono riportate le regole generali per le espressioni lambda:The general rules for lambdas are as follows:

  • L'espressione lambda deve contenere lo stesso numero di parametri del tipo delegato.The lambda must contain the same number of parameters as the delegate type.

  • Ogni parametro di input nell'espressione lambda deve essere convertibile in modo implicito nel parametro del delegato corrispondente.Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.

  • Il valore restituito dell'espressione lambda, se presente, deve essere convertibile in modo implicito nel tipo restituito del delegato.The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.

Si noti che le espressioni lambda non hanno un tipo poiché Common Type System non ha alcun concetto intrinseco di "espressione lambda".Note that lambda expressions in themselves do not have a type because the common type system has no intrinsic concept of "lambda expression." In alcuni casi, tuttavia, può essere utile fare riferimento in modo informale al "tipo" di un'espressione lambda.However, it is sometimes convenient to speak informally of the "type" of a lambda expression. In questi casi, per tipo si intende il tipo delegato o il tipo Expression in cui viene convertita l'espressione lambda.In these cases the type refers to the delegate type or Expression type to which the lambda expression is converted.

Ambito delle variabili nelle espressioni lambdaVariable Scope in Lambda Expressions

Le espressioni lambda possono fare riferimento alle variabili esterne (vedere Metodi anonimi) presenti nell'ambito del metodo che definisce la funzione lambda oppure nell'ambito del tipo che contiene l'espressione 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. Le variabili acquisite in questo modo vengono archiviate per poter essere utilizzate nell'espressione lambda anche se le variabili diventano esterne all'ambito e vengono sottoposte a Garbage Collection.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. Una variabile esterna deve essere assegnata prima di poter essere utilizzata in un'espressione lambda.An outer variable must be definitely assigned before it can be consumed in a lambda expression. Nell'esempio seguente vengono illustrate queste regole: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();  
    }  
}  

Le regole seguenti si applicano all'ambito delle variabili nelle espressioni lambda:The following rules apply to variable scope in lambda expressions:

  • Una variabile acquisita non sarà sottoposta a Garbage Collection finché il delegato a cui fa riferimento non diventa idoneo per il Garbage Collection.A variable that is captured will not be garbage-collected until the delegate that references it becomes eligible for garbage collection.

  • Le variabili introdotte all'interno di un'espressione lambda non sono visibili nel metodo esterno.Variables introduced within a lambda expression are not visible in the outer method.

  • Un'espressione lambda non può acquisire direttamente un parametro in, ref o out da un metodo contenitore.A lambda expression cannot directly capture an in, ref, or out parameter from an enclosing method.

  • Un'istruzione return in un'espressione lambda non causa la restituzione del metodo contenitore.A return statement in a lambda expression does not cause the enclosing method to return.

  • Un'espressione lambda non può contenere un'istruzione goto , break o continue , inclusa nella funzione lambda se la destinazione dell'istruzione jump è esterna al blocco.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. È altresì errato inserire all'esterno del blocco della funzione lambda un'istruzione jump se la destinazione è interna al blocco.It is also an error to have a jump statement outside the lambda function block if the target is inside the block.

Specifiche del linguaggio C#C# Language Specification

Per altre informazioni, vedere la specifica del linguaggio C#.For more information, see the C# Language Specification. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.The language specification is the definitive source for C# syntax and usage.

Delegates, Events, and Lambda Expressions (Delegati, eventi ed espressioni lambda) in 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

Vedere ancheSee Also

Guida per programmatori C#C# Programming Guide
LINQ (Language-Integrated Query)LINQ (Language-Integrated Query)
Metodi anonimiAnonymous Methods
isis
Alberi delle espressioniExpression Trees
Esempi C# di Visual Studio 2008 (vedere i file di query di esempio LINQ e il programma XQuery)Visual Studio 2008 C# Samples (see LINQ Sample Queries files and XQuery program)
Recursive lambda expressions (Espressioni lambda ricorsive)Recursive lambda expressions