Confronto tra sintassi di query LINQ e sintassi dei metodi (C#)

La maggior parte delle query nella documentazione introduttiva di LINQ è scritta come espressioni di query utilizzando la sintassi di query dichiarativa introdotta in C# 3.0. .NET Common Language Runtime (CLR) non è tuttavia in grado di comprendere la sintassi di query. Pertanto, in fase di compilazione, le espressioni di query vengono convertite in chiamate al metodo in modo da poter essere utilizzate da CLR. Questi metodi sono denominati operatori query standard e includono Where, Select, GroupBy, Join, Max, Average e così via. È possibile chiamarli direttamente utilizzando la sintassi del metodo anziché la sintassi della query.

È consigliabile generalmente la sintassi della query poiché è più semplice e più leggibile ma non esiste una differenza semantica tra la sintassi del metodo e la sintassi della query. Inoltre, alcune query, ad esempio quelle che recuperano il numero di elementi che corrispondono a una condizione specificata o che recuperano l'elemento che ha il valore massimo in una sequenza di origine, possono essere espresse solo come chiamate al metodo. Nella documentazione di riferimento per gli operatori di query standard dello spazio dei nomi System.Linq viene utilizzata generalmente la sintassi del metodo. Pertanto, anche quando si comincia a scrivere le query LINQ, è utile acquisire dimestichezza con l'utilizzo della sintassi del metodo nelle query e nelle espressioni di query.

Metodi di estensione degli operatori di query standard

Nell'esempio seguente viene illustrata un'espressione di query semplice e la query equivalente a livello semantico scritta come query basata sul metodo.

class QueryVMethodSyntax
{
    static void Main()
    {
        int[] numbers = { 5, 10, 8, 3, 6, 12};

        //Query syntax:
        IEnumerable<int> numQuery1 = 
            from num in numbers
            where num % 2 == 0
            orderby num
            select num;

        //Method syntax:
        IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);

        foreach (int i in numQuery1)
        {
            Console.Write(i + " ");
        }
        Console.WriteLine(System.Environment.NewLine);
        foreach (int i in numQuery2)
        {
            Console.Write(i + " ");
        }

        // Keep the console open in debug mode.
        Console.WriteLine(System.Environment.NewLine);
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
}
/*
    Output:
    6 8 10 12
    6 8 10 12
 */

L'output dei due esempi è identico. Il tipo della variabile di query è uguale in entrambi i formati: IEnumerable<T>.

Per comprendere la query basata sul metodo, è utile esaminarla più dettagliatamente. Sul lato destro dell'espressione la clausola where viene ora espressa come un metodo di istanza sull'oggetto numbers che, come descritto in precedenza, ha un tipo di IEnumerable<int>. Se si ha dimestichezza con l'interfaccia IEnumerable<T> generica, è noto che non dispone di un metodo Where. Tuttavia, se si richiama l'elenco di completamento IntelliSense nell'IDE di Visual Studio, non solo sarà disponibile un metodo Where, ma molti altri metodi quali Select, SelectMany, Join e Orderby. Questi sono tutti operatori di query standard.

Operatori query standard in Intellisense

Sebbene possa sembrare che IEnumerable<T> sia stato ridefinito per includere questi metodi aggiuntivi, di fatto non è così. Gli operatori di query standard vengono implementati come un nuovo tipo di metodo denominato metodo di estensione. I metodi di estensione "estendono" un tipo esistente e possono essere chiamati come se fossero metodi di istanza sul tipo. Gli operatori di query standard estendono IEnumerable<T> ed è per questo motivo che è possibile scrivere numbers.Where(...).

Per iniziare a utilizzare LINQ, è importante comprendere come inserire i metodi di estensione nell'ambito dell'applicazione mediante le direttive using corrette. Tale procedura viene illustrata anche in Procedura: creare un progetto LINQ. Dal punto di vista dell'applicazione, un metodo di estensione e un metodo di istanza regolare sono uguali.

Per ulteriori informazioni sui metodi di estensione, vedere Metodi di estensione (Guida per programmatori C#). Per ulteriori informazioni sugli operatori di query standard, vedere Cenni preliminari sugli operatori di query standard. Alcuni provider LINQ, ad esempio LINQ to SQL e LINQ to XML, implementano operatori di query standard personalizzati e metodi di estensione aggiuntivi per altri tipi oltre a IEnumerable<T>.

Espressioni lambda

Nell'esempio precedente l'espressione condizionale (num % 2 == 0) viene passata come argomento in linea al metodo Where: Where(num => num % 2 == 0). Questa espressione in linea viene denominata espressione lambda. È il modo più semplice per scrivere il codice che altrimenti dovrebbe essere scritto in modo molto più complesso come metodo anonimo o delegato generico o come struttura ad albero dell'espressione. In C# => è l'operatore lambda, che viene letto come "fino a". num sulla sinistra dell'operatore è la variabile di input che corrisponde a num nell'espressione di query. Il compilatore può dedurre il tipo di num poiché numbers è un tipo IEnumerable<T> generico. Il corpo della lambda è identico all'espressione nella sintassi della query o in un'altra espressione o istruzione C# e può includere chiamate al metodo e altra logica complessa. Il "valore restituito" è il risultato dell'espressione.

Per iniziare a utilizzare LINQ, non è necessario utilizzare le espressioni lambda. Tuttavia, alcune query possono essere espresse solo nella sintassi del metodo e possono richiedere le espressioni lambda. Dopo aver acquisito dimestichezza con le espressioni lambda, si scoprirà che sono uno strumento potente e flessibile nella casella degli strumenti LINQ. Per ulteriori informazioni, vedere Espressioni lambda (Guida per programmatori C#).

Componibilità delle query

Nell'esempio di codice precedente si noti che il metodo OrderBy viene richiamato utilizzando l'operatore punto nella chiamata a Where. Where produce una sequenza filtrata, quindi Orderby agisce su tale sequenza ordinandola. Poiché le query restituiscono un oggetto IEnumerable, è necessario comporle nella sintassi del metodo concatenando le chiamate al metodo. Questa operazione viene eseguita automaticamente dal compilatore quando si scrivono le query utilizzando la sintassi della query. E poiché una variabile di query non archivia i risultati della query, è possibile modificarla o utilizzarla come base per una nuova query in qualsiasi momento, anche dopo l'esecuzione.

Vedere anche

Altre risorse

Nozioni di base su LINQ in C#