-----------------------------------

Acquista i software ArcGIS tramite Studio A&T srl, rivenditore autorizzato dei prodotti Esri.

I migliori software GIS, il miglior supporto tecnico!

I migliori software GIS, il miglior supporto tecnico!
Azienda operante nel settore GIS dal 2001, specializzata nell’utilizzo della tecnologia ArcGIS e aderente ai programmi Esri Italia Business Network ed Esri Partner Network

-----------------------------------



mercoledì 21 aprile 2010

Lambda con Standard Query Operators, Extension method e Type Inference in Lambdas

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

Le Lambda sono utilizzate nelle LINQ queries method-based come argomenti per standand query in metodi come Where


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> myFunc dove int è un parametro di input e bool è il valore restituito. Il valore restituito è sempre specificato nel tipo dell'ultimo parametro.
Func<int,string,bool> definisce un delegato con 2 parametri di input, int e string e restituisce un tipo bool.
Il seguente delegato Func, quando è invocato, restituirà true o false per indicare se il parametro di input è 5:

Func myFunc = x => x == 5;

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);

                    }