Tra le novità di C#3.0 e VB9 sicuramente le lambda expressions sono le più "ostiche" da comprendere, vuoi per il nome che incute timore , vuoi per lo strano simbolo "=>" che si legge "Goes To" oppure semplicemente perchè incontrate per la prima volta con LINQ e quindi in un contesto di per se non chiaro, almeno inizialmente.
In realtà le lambda altro non sono che una versione riveduta ed "epurata" degli anonymous methods che chi usa C#2.0 sicuramente conosce e utilizza.
Consideriamo tre delegates:
Usando gli anonymous methods lo stesso delegate in C#2.0 può essere invocato in questo modo:
Immaginiamo ora di rimuovere alcune informazioni "superflue" come la keyword delegate, aggiungendo il simbolo "=>" tra i parametri e il corpo del anonymous method e spostando tutto su una singola riga:
Et voilà ecco una lambda expression... (o statement lambda se preferite...)
Visto che il compilatore C#3.0 è molto smart è possibile semplificare ulteriormente l'espressione facendo dedurre il tipo di a, b e quello di ritorno dal delegate Sum al quale la lambda è associata e rimuovere la keyword return ottenendo:
Nel caso ci sia un solo parametro le parentesi si possono eliminare come nel caso di un ipotetica funzione IncreaseByOne
In assenza di parametri, come nel caso del delegate 3, le parentesi devono necessariamente essere specificate:
Il delegate 2 rappresenta un generica funzione MyFunc che opera e restituisce un tipo T, in questo caso in base a quanto detto finora è quindi possibile dichairare una lambda expression Multiply in questo modo:
In realtà il delegate 2 è inutile, in quanto nel framework 3.5 esiste già un delegate generico Func<T,TResult> con vari overload che rappresenta una generica funzione con un numero variabile di parametri T in ingresso (da zero a quattro) e un generico valore TResult (definito in ultima posizione) di ritorno. Di conseguenza l'esempio precedente può essere riscritto come segue:
Il codice eseguito dalla lambda è stato fin'ora composto da espressioni molto semplici (tipo a+b), C#3.0, a differenza di VB9, consente di definire dei lambda statements ovvero delle lambda che contengono più di una semplice espressione e che sono, a tutti gli effetti, degli anonymous methods come nell'esempio seguente:
Expression Trees
Una lambda expression può essere definita attraverso un Expression Tree ovvero una classe Expression<T> definita in System.Linq.Expression con la differenza che in questo caso l'espressione viene effettivamente trasformata in codice IL al momento della sua esecuzione e non a compile time e questo IL costruisce un albero di expressioni che descrivono la lambda expression associata.
L'utilizzo delle Expression Tree è legato ai Query providers di LINQ percui, come MSDN stesso cita, a meno che non dobbiate creare un vostro specifico LINQ provider o un vostro query language potete ignorare i dettagli relativi agli expression trees.
Riprendendo la lambda expression precedente
ecco come esprimerla usando un expression tree:
notate, come in questo caso sia necessario compilare l'espressione attraverso il metodo Compile prima di poterla utilizzare.
VB9
La sintassi per definire delle lambda expression in VB9 sfrutta la keyword Function, rifacendoci all'esempio precedente ecco come associare un delegate Sum ad una lambda expression (il codice richiede la June CTP o successiva)
Dalla Beta2 la definizione della lambda verrà ulteriormente semplificata rimuovendo il modificatore ByVal che precede i parametri, nella June CTP non è possibile rimuoverlo.
Come accennato in precedenza VB9 permette di definire delle lambda expressions ma non dei lambda statements, ciò si traduce nel fatto che in VB9 manca una vera implementazione degli anonymous methods , a differenza di C# è però possibile associare una lambda expression ad una variabile il cui tipo è dedotto implicitamente (Option Infer On) ovvero:
Ovviamente le lambda entrano prepotentemente in gioco nell'architettura di LINQ, ma come avete potuto vedere possono essere sicuramente utili in parecchie altre occasioni.