Condividi tramite


Procedura dettagliata: scrittura di query in C# (LINQ)

Aggiornamento: novembre 2007

In questa procedura dettagliata vengono descritte le nuove funzionalità del linguaggio C# 3.0 e viene illustrato il modo in cui tali funzionalità vengono utilizzate per scrivere le espressioni di query LINQ. Dopo avere completato questa procedura dettagliata sarà possibile passare agli esempi e alla documentazione per il provider LINQ specifico desiderato, ad esempio LINQ to SQL, LINQ to DataSets o LINQ to XML.

Prerequisiti

Questa procedura dettagliata richiede Visual Studio 2008.

Collegamento a video Per una dimostrazione video, vedere Procedura relativa a contenuti video: scrittura di query in C# (LINQ) (informazioni in lingua inglese).

Creazione di un progetto C#

Per creare un progetto C# per la versione 3.5 di .NET Framework

  1. Avviare Visual Studio.

  2. Scegliere Nuovo dal menu File, quindi Progetto.

  3. Nell'angolo superiore destro della finestra di dialogo Nuovo progetto sono presenti tre icone. Fare clic sull'icona a sinistra e verificare che sia selezionato .NET Framework versione 3.5.

  4. Fare clic sull'icona Applicazione console sotto Modelli Visual Studio installati.

  5. Assegnare all'applicazione un nuovo nome o accettare il nome predefinito e fare clic su OK.

  6. Il progetto include un riferimento a System.Core.dll e una direttiva using per lo spazio dei nomi System.Linq.

Creazione di un'origine dati in memoria

L'origine dati per le query è un semplice elenco di oggetti Student. Ogni record Student contiene un nome, un cognome e una matrice di valori interi che rappresentano i punteggi dei test della classe. Copiare questo codice nel progetto. Tenere presente le seguenti caratteristiche:

  • La classe Student è costituita da proprietà implementate automaticamente.

  • Ogni studente nell'elenco viene inizializzato con un inizializzatore di oggetto.

  • L'elenco stesso viene inizializzato con un inizializzatore di insieme.

Tutta la struttura dei dati verrà inizializzata e ne verrà creata un'istanza senza chiamate esplicite a un costruttore o accesso esplicito a un membro. Per ulteriori informazioni su queste nuove funzionalità, vedere Proprietà implementate automaticamente (Guida per programmatori C#) e Inizializzatori di oggetto e di insieme (Guida per programmatori C#).

Per aggiungere l'origine dati

  • Aggiungere la classe Student e l'elenco di studenti inizializzato alla classe Program nel progetto.

    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }
    
    // Create a data source by using a collection initializer.
    static List<Student> students = new List<Student>
    {
       new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
       new Student {First="Claire", Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
       new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}},
       new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}},
       new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}},
       new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}},
       new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}},
       new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}},
       new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}},
       new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}},
       new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}},
       new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91} }
    };
    

Per aggiungere un nuovo oggetto Student all'elenco Students

  • Aggiungere un nuovo oggetto Student all'elenco Students e utilizzare un nome e i punteggi dei test desiderati. Provare a immettere tutte le informazioni sul nuovo studente in modo da acquisire dimestichezza con la sintassi per l'inizializzatore di oggetto.

Creazione della query

Per creare una query semplice

  • Nel metodo Main dell'applicazione creare una query semplice che, quando eseguita, genererà un elenco di tutti gli studenti il cui punteggio del primo test sia maggiore di 90. Il tipo della query è IEnumerable<Student> poiché è selezionato l'intero oggetto Student. Sebbene nel codice poteva essere utilizzata la tipizzazione implicita mediante la parola chiave var, è stata utilizzata la tipizzazione esplicita per illustrare dettagliatamente i risultati. Per ulteriori informazioni su var, vedere Variabili locali tipizzate in modo implicito (Guida per programmatori C#).

    Tenere inoltre presente che la variabile di intervallo della query, student, funge da riferimento a ogni oggetto Student presente nell'origine, fornendo l'accesso al membro per ogni oggetto.

// Create the query.
// studentQuery is an IEnumerable<Student>
var studentQuery =
    from student in students
    where student.Scores[0] > 90
    select student;

Esecuzione della query

Per eseguire la query

  1. Scrivere ora il ciclo foreach che consente di eseguire la query. In relazione al codice tenere presente quanto segue:

    • È possibile accedere a ogni elemento della sequenza restituita mediante la variabile di iterazione nel ciclo foreach.

    • Il tipo di questa variabile è Student e il tipo della variabile di query è compatibile, IEnumerable<Student>.

  2. Dopo avere aggiunto questo codice, compilare ed eseguire l'applicazione premendo CTRL + F5 per visualizzare i risultati nella finestra della console.

// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
    Console.WriteLine("{0}, {1}", student.Last, student.First);
}

Per aggiungere un'altra condizione di filtro

  • È possibile combinare più condizioni booleane nella clausola where in modo da perfezionare ulteriormente la query. Nel codice seguente viene aggiunta una condizione in modo che la query restituisca gli studenti il cui primo punteggio sia maggiore di 90 e il cui ultimo punteggio sia minore di 80. La clausola where deve essere analoga al codice seguente.

    where student.Scores[0] > 90 && student.Scores[3] < 80
    

    Per ulteriori informazioni, vedere Clausola where (Riferimento C#).

Modifica della query

Per ordinare i risultati

  1. Sarà più semplice analizzare i risultati se vengono ordinati. È possibile ordinare la sequenza restituita in base a qualsiasi campo accessibile negli elementi di origine. Ad esempio, la clausola orderby riportata di seguito ordina i risultati alfabeticamente dalla A alla Z in base al cognome di ogni studente. Aggiungere alla query la clausola orderby riportata di seguito, subito dopo l'istruzione where e prima dell'istruzione select:

    orderby student.Last ascending
    
  2. Modificare ora la clausola orderby in modo da disporre i risultati in ordine inverso in base al punteggio del primo test, iniziando dal punteggio più alto fino a quello più basso.

    orderby student.Scores[0] descending
    
  3. Modificare la stringa di formato WriteLine in modo da poter visualizzare i punteggi:

    Console.WriteLine("{0}, {1} {2}", s.Last, s.First, s.Scores[0]);
    

    Per ulteriori informazioni, vedere Clausola orderby (Riferimento C#).

Per raggruppare i risultati

  1. Il raggruppamento è una funzionalità potente nelle espressioni di query. Una query con una clausola group genera una sequenza di gruppi e ogni gruppo contiene un oggetto Key e una sequenza costituita da tutti i membri di tale gruppo. Nella nuova query riportata di seguito gli studenti vengono raggruppati utilizzando la prima lettera del cognome come chiave.

    // studentQuery2 is an IEnumerable<IGrouping<char, Student>>
    var studentQuery2 =
        from student in students
        group student by student.Last[0];
    
  2. Il tipo della query è stato ora modificato. Vengono ora generate una sequenza di gruppi con il tipo char come chiave e una sequenza di oggetti Student. Poiché il tipo della query è stato modificato, nel codice seguente viene modificato anche il ciclo di esecuzione foreach:

    // studentGroup is a IGrouping<char, Student>
    foreach (var studentGroup in studentQuery2)
    {
        Console.WriteLine(studentGroup.Key);
        foreach (Student student in studentGroup)
        {
            Console.WriteLine("   {0}, {1}",
                      student.Last, student.First);
        }
    }
    
  3. Premere CTRL + F5 per eseguire l'applicazione e visualizzare i risultati nella finestra della console.

    Per ulteriori informazioni, vedere Clausola group (Riferimento C#).

Per creare le variabili tipizzate in modo implicito

  • Codificare in modo esplicito IEnumerables di IGroupings può risultare noioso. È possibile scrivere la stessa query e il ciclo foreach in modo notevolmente più pratico utilizzando var. La parola chiave var non modifica i tipi degli oggetti ma indica solo al compilatore di dedurre i tipi. Impostare il tipo di studentQuery e la variabile di iterazione group su var e rieseguire la query. Nel ciclo foreach interno la variabile di iterazione è ancora tipizzata come Student e la query funziona esattamente come prima. Impostare la variabile di iterazione s su var e rieseguire la query. Si otterranno esattamente gli stessi risultati.

    var studentQuery3 =
        from student in students
        group student by student.Last[0];
    
    foreach (var groupOfStudents in studentQuery3)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
             Console.WriteLine("   {0}, {1}",
                 student.Last, student.First);
        }
    }
    

    Per ulteriori informazioni su var, vedere Variabili locali tipizzate in modo implicito (Guida per programmatori C#).

Per ordinare i gruppi in base al valore della chiave

  • Quando si esegue la query precedente, i gruppi non sono in ordine alfabetico. Per modificare questo comportamento, è necessario fornire la clausola orderby dopo la clausola group. Per utilizzare la clausola orderby, è necessario però utilizzare prima un identificatore che funga da riferimento ai gruppi creati dalla clausola group. Fornire l'identificatore utilizzando la parola chiave into, come segue:

    var studentQuery4 =
        from student in students
        group student by student.Last[0] into studentGroup
        orderby studentGroup.Key
        select studentGroup;
    
    foreach (var groupOfStudents in studentQuery4)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
            Console.WriteLine("   {0}, {1}",
                student.Last, student.First);
        }
    }
    
    

    Quando si esegue questa query, i gruppi verranno ora ordinati alfabeticamente.

Per introdurre un identificatore utilizzando let

  • È possibile utilizzare la parola chiave let per introdurre un identificatore per qualsiasi risultato dell'espressione di query. Questo identificatore può risultare utile come nell'esempio seguente o può migliorare le prestazioni archiviando i risultati di un'espressione in modo da non doverla calcolare più volte.

    // studentQuery5 is an IEnumerable<string>
    // This query returns those students whose
    // first test score was higher than their
    // average score.
    var studentQuery5 =
        from student in students
        let totalScore = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where totalScore / 4 < student.Scores[0]
        select student.Last + " " + student.First;
    
    foreach (string s in studentQuery5)
    {
        Console.WriteLine(s);
    }
    

    Per ulteriori informazioni, vedere Clausola let (Riferimento C#).

Per utilizzare la sintassi del metodo in un'espressione di query

  • Come descritto in Sintassi delle query e sintassi dei metodi (LINQ), alcune operazioni di query possono essere espresse solo utilizzando la sintassi del metodo. Nel codice seguente viene calcolato il punteggio totale per ogni Student nella sequenza di origine e viene quindi chiamato il metodo Average() sui risultati della query per calcolare il punteggio medio della classe. Notare l'utilizzo delle parentesi nell'espressione di query.

        var studentQuery6 = 
            from student in students
            let totalScore = student.Scores[0] + student.Scores[1] +
                student.Scores[2] + student.Scores[3]
            select totalScore;
    
        double averageScore = studentQuery6.Average();
    Console.WriteLine("Class average score = {0}", averageScore);
    

Per trasformare o proiettare nella clausola select

  1. Una query genera normalmente una sequenza i cui elementi differiscono dagli elementi delle sequenze di origine. Eliminare o impostare come commento la query precedente e il ciclo di esecuzione e sostituirli con il codice seguente. La query restituisce una sequenza di stringhe (non Students) che si riflette nel ciclo foreach.

    IEnumerable<string> studentQuery7 =
        from student in students
        where student.Last == "Garcia"
        select student.First;
    
    Console.WriteLine("The Garcias in the class are:");
    foreach (string s in studentQuery7)
    {
        Console.WriteLine(s);
    }
    
    
  2. Il codice illustrato in precedenza in questa procedura dettagliata ha riportato che il punteggio medio della classe è approssimativamente 334. Per generare una sequenza di Students il cui punteggio totale sia maggiore del punteggio medio della classe, insieme ai relativi Student ID, è possibile utilizzare un tipo anonimo nell'istruzione select:

    var studentQuery8 =
        from student in students
        let x = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where x > averageScore
        select new { id = student.ID, score = x };
    
    foreach (var item in studentQuery8)
    {
        Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score);
    }
    
    

Passaggi successivi

Dopo aver acquisito dimestichezza con le caratteristiche principali delle query in C#, è possibile leggere la documentazione e gli esempi per il tipo specifico di provider LINQ desiderato:

LINQ to SQL

LINQ to DataSet

LINQ to XML

LINQ to Objects

Esempi C# LINQ

Vedere anche

Concetti

Espressioni query LINQ (Guida per programmatori C#)

Risorse LINQ supplementari

Altre risorse

LINQ (Language-Integrated Query)

Nozioni di base su LINQ in C#