parola chiave delegato vs. notazione lambda

Una volta compilato, c’è una differenza tra:

delegate { x = 0; } 

e

 () => { x = 0 } 

?

Risposta breve: no.

Risposta più lunga che potrebbe non essere pertinente:

  • Se assegni il lambda a un tipo di delegato (come Func o Action ) riceverai un delegato anonimo.
  • Se assegni il lambda a un tipo di espressione, otterrai un albero di espressioni invece di un delegato anonimo. L’albero delle espressioni può quindi essere compilato con un delegato anonimo.

Modifica: ecco alcuni link per le espressioni.

  • System.Linq.Expression.Expression (TDelegate) (inizia qui).
  • Linq in memoria con i delegati (come System.Func) utilizza System.Linq.Enumerable . Da Linq a SQL (e qualsiasi altra cosa) con espressioni utilizza System.Linq.Queryable . Controlla i parametri su questi metodi.
  • Una spiegazione di ScottGu . In poche parole, Linq in-memory produrrà alcuni metodi anonimi per risolvere la query. Linq to SQL produrrà un albero di espressioni che rappresenta la query e quindi tradurrà quell’albero in T-SQL. Linq to Entities produrrà un albero di espressioni che rappresenta la query e quindi tradurrà quell’albero in SQL appropriato della piattaforma.

Mi piace la risposta di David, ma pensavo di essere pedante. La domanda dice “Una volta compilato” – il che suggerisce che entrambe le espressioni sono state compilate. Come potrebbero entrambi compilare, ma con uno convertito in delegato e uno in un albero di espressioni? È difficile: devi usare un’altra caratteristica dei metodi anonimi; l’unico che non è condiviso dalle espressioni lambda. Se si specifica un metodo anonimo senza specificare un elenco di parametri, è compatibile con qualsiasi tipo di delegato che restituisce void e senza alcun parametro out . Armati di questa conoscenza, dovremmo essere in grado di build due overload per rendere le espressioni completamente non ambigue ma molto diverse.

Ma il disastro colpisce! Almeno con C # 3.0, non puoi convertire un’espressione lambda con un corpo di blocco in un’espressione – né puoi convertire un’espressione lambda con un assegnamento nel corpo (anche se è usato come valore di ritorno). Questo potrebbe cambiare con C # 4.0 e .NET 4.0, che consentono di esprimere di più in un albero di espressioni. Quindi, in altre parole, con gli esempi che MojoFilter ha dato, i due saranno quasi sempre convertiti nella stessa cosa. (Maggiori dettagli in un minuto.)

Possiamo usare il trucco dei parametri delegati se cambiamo i corpi un po ‘però:

 using System; using System.Linq.Expressions; public class Test { static void Main() { int x = 0; Foo( () => x ); Foo( delegate { return x; } ); } static void Foo(Func action) { Console.WriteLine("I suspect the anonymous method..."); } static void Foo(Expression> func) { Console.WriteLine("I suspect the lambda expression..."); } } 

Ma aspetta! Possiamo distinguere tra i due anche senza usare alberi di espressione, se siamo abbastanza furbi. L’esempio seguente utilizza le regole di risoluzione del sovraccarico (e il trucco di corrispondenza dei delegati anonimi) …

 using System; using System.Linq.Expressions; public class Base { public void Foo(Action action) { Console.WriteLine("I suspect the lambda expression..."); } } public class Derived : Base { public void Foo(Action action) { Console.WriteLine("I suspect the anonymous method..."); } } class Test { static void Main() { Derived d = new Derived(); int x = 0; d.Foo( () => { x = 0; } ); d.Foo( delegate { x = 0; } ); } } 

Ahia. Ricorda i bambini, ogni volta che sovraccarichi un metodo ereditato da una class base, un piccolo gattino inizia a piangere.

David B è corretto. Nota che ci possono essere dei vantaggi nell’uso degli alberi di espressione. LINQ to SQL esaminerà l’albero delle espressioni e lo convertirà in SQL.

Puoi anche fare scherzi con lamdas e alberi di espressione per passare in modo efficace i nomi dei membri della class a un framework in modo sicuro per il refactoring. Moq è un esempio di questo.

Nei due esempi sopra non c’è differenza, zero.

L’espressione:

 () => { x = 0 } 

è un’espressione Lambda con corpo dell’istruzione, quindi non può essere compilata come un albero di espressioni. Infatti non si compila neanche perché ha bisogno di un punto e virgola dopo lo 0:

 () => { x = 0; } // Lambda statement body () => x = 0 // Lambda expression body, could be an expression tree. 

C’è una differenza

Esempio:

 var mytask = Task.Factory.StartNew(() => { Thread.Sleep(5000); return 2712; }); mytask.ContinueWith(delegate { _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture)); }); 

E sostituisco con lambda: (errore)

 var mytask = Task.Factory.StartNew(() => { Thread.Sleep(5000); return 2712; }); mytask.ContinueWith(()=> { _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture)); }); 

Alcuni di base qui.

Questo è un metodo anonimo

 (string testString) => { Console.WriteLine(testString); }; 

Poiché il metodo anonimo non ha alcun nome, abbiamo bisogno di un delegato nel quale possiamo assegnare entrambi questi metodi o espressioni. per esempio

 delegate void PrintTestString(string testString); // declare a delegate PrintTestString print = (string testString) => { Console.WriteLine(testString); }; print(); 

Lo stesso con l’espressione lambda. Di solito abbiamo bisogno di un delegato per usarli

 s => s.Age > someValue && s.Age < someValue // will return true/false 

Possiamo usare un delegato func per usare questa espressione.

 Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ; bool result = checkStudentAge ( Student Object);