Una lambda expression è una funzione anonima che può contenere espressioni e blocchi di codice, e può essere usata per creare delegati o tipi di espressione ad albero.
Quando usi una sintassi method-based per chiamare il metodo Where in una classe Enumerable il parametro è un delegato di tipo Func(T, TResult)
Una lambda expression è il modo più adatto per creare quel delegato.
La forma di una lambda expression è:
(input parameters) => expression
e restituisce il risultato dell'espressione.
Le parentesi sono sempre obbigatorie a meno di avere un solo parametro:
Esempio con due parametri con dichiarati i tipi:
(int x, string s) => s.Length > x
Esempio con due parametri:
(x, y) => x == y
Esempio senza parametri: () => SomeMethod()
Lambda con blocco di codice
(input parameters) => {statement;}
Esempio Lambda con blocco di codice
n => { string s = n + " " + "World"; Console.WriteLine(s); };
Lambda con Standard Query Operators
Molte Standard query operators hanno come parametro di input un delegato generico della famiglia Func(T, TResult). Questi delegati usano i tipi dei parametri per definire il numero ed il tipo di parametri, e restituire il tipo di delegato.
Il delegato può essere utilizzato come Func<int,bool>
Func<int,string,bool>
Il seguente delegato Func, quando è invocato, restituirà true o false per indicare se il parametro di input è 5:
Func
bool result = myFunc(4); // qui chiaramente restituisce false
Type Inference in Lambda
Quando scrivi lambda, spesso non devi specificare il tipo per i parametri di input perchè il compilatore può capire il tipo in base al corpo della lambda, al sottostante tipo di delegato e ad altri fattori come descritto nelle specifiche del linguaggio C# 3.0.
Per la maggior parte delle standard query operators, il primo input è il tipo degli elementi nella sequenza della sorgente. Così se stai interrogando un IEnumerable<IFeature>, successivamente la variable di input sarà vista come un oggetto IFeature che significa che hai accesso ai suoi metodi e proprietà:
In questo esempio k è un tipo IEnumerable<IFeature>
decimal t = k.Where(i => (i.get_Value(idxName).ToString() == "Amsterdam")).Sum(i => Convert.ToDecimal(i.get_Value(idxShapeLength)));
Mettiamo insieme tutte le nozioni ed applichiamole ad un esempio utilizzando anche gli arcobjects:
public static class ExtensionsMethod
{
public static IEnumerable<T> AsEnumerable<U,T>(this U cursor, Func<T> next) where T:class
{
T current = next();
while (current != default(T))
{
yield return current;
current = next();
}
}
public static IField get_Field(this IFields fields, string FieldName)
{
int i = fields.FindField(FieldName);
return (i == -1) ? null : fields.get_Field(i);
}
}
IPropertySet propertySet = new PropertySetClass();
propertySet.SetProperty("DATABASE", @"C:\Program Files\ArcGIS\DeveloperKit\SamplesNET\data\Atlanta.gdb");
Type factoryType = Type.GetTypeFromProgID(
"esriDataSourcesGDB.FileGDBWorkspaceFactory");
IWorkspaceFactory2 workspaceFactory = (IWorkspaceFactory2)Activator.CreateInstance(factoryType);
IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)workspaceFactory.Open(propertySet, 0);
IFeatureClass featureClass = featureWorkspace.OpenFeatureClass("streets");
using (ComReleaser comReleaser = new ComReleaser())
{
IFeatureCursor featureCursor = featureClass.Search(null,true);
comReleaser.ManageLifetime(featureCursor);
IFields fields = featureClass.Fields;
int idxName = fields.FindField("NAME");
int idxType = fields.FindField("TYPE");
int idxShapeLength = fields.FindField(featureClass.LengthField.Name);
IEnumerable<IFeature> k = featureCursor.AsEnumerable(() => featureCursor.NextFeature());
decimal t = k.Where(i => (i.get_Value(idxName).ToString() == "Amsterdam")).Sum(i => Convert.ToDecimal(i.get_Value(idxShapeLength)));
Console.Write("La lunghezza della via {0} è {1}", "Amsterdam", t);
}