Condividi tramite


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

In questa procedura guidata vengono illustrate le funzionalità del linguaggio C# utilizzate per scrivere 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

In questa procedura dettagliata richiede le funzionalità introdotte in Visual Studio 2008.

Collegamento a video Per una versione video di questo argomento, 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

  1. Avviare Visual Studio.

  2. Nella barra del menu, scegliere File, Nuovo, Progetto.

    Verrà visualizzata la finestra di dialogo Nuovo progetto.

  3. Espandere Installato, espandere Modelli, espandere **Visual C#**e quindi scegliere Applicazione console.

  4. Nella casella di testo Nome, un altro nome o accettare il nome predefinito e quindi scegliere il pulsante OK.

    Il nuovo progetto verrà visualizzato in Esplora soluzioni.

  5. 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 raccolta.

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 raccolte (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 verrà eseguita, produrrà un elenco di tutti gli studenti il cui punteggio nel primo test era superiore a 90. Si noti che, poiché viene selezionato l'intero oggetto Student, il tipo della query è IEnumerable<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. 
// The first line could also be written as "var studentQuery ="
IEnumerable<Student> 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);
}

// Output: 
// Omelchenko, Svetlana 
// Garcia, Cesar 
// Fakhouri, Fadi 
// Feng, Hanying 
// Garcia, Hugo 
// Adams, Terry 
// Zabokritski, Eugene 
// Tucker, Michael

Per aggiungere un'altra condizione di filtro

  • È possibile combinare più condizioni booleane nella clausola where in modo da perfezionare ulteriormente la query. Il codice seguente aggiunge una condizione in modo che la query restituisca gli studenti di cui il primo punteggio era superiore a 90 e l'ultimo inferiore a 80. La clausola where dovrebbe 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}", student.Last, student.First, student.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);
        }
    }
    
    // Output: 
    // O 
    //   Omelchenko, Svetlana 
    //   O'Donnell, Claire 
    // M 
    //   Mortensen, Sven 
    // G 
    //   Garcia, Cesar 
    //   Garcia, Debra 
    //   Garcia, Hugo 
    // F 
    //   Fakhouri, Fadi 
    //   Feng, Hanying 
    // T 
    //   Tucker, Lance 
    //   Tucker, Michael 
    // A 
    //   Adams, Terry 
    // Z 
    //   Zabokritski, Eugene
    
  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. Modificare il tipo di studentQuery e la variabile di iterazione groupa 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);
        }
    }
    
    // Output: 
    // O 
    //   Omelchenko, Svetlana 
    //   O'Donnell, Claire 
    // M 
    //   Mortensen, Sven 
    // G 
    //   Garcia, Cesar 
    //   Garcia, Debra 
    //   Garcia, Hugo 
    // F 
    //   Fakhouri, Fadi 
    //   Feng, Hanying 
    // T 
    //   Tucker, Lance 
    //   Tucker, Michael 
    // A 
    //   Adams, Terry 
    // Z 
    //   Zabokritski, Eugene
    

    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);
        }
    }
    
    // Output: 
    //A 
    //   Adams, Terry 
    //F 
    //   Fakhouri, Fadi 
    //   Feng, Hanying 
    //G 
    //   Garcia, Cesar 
    //   Garcia, Debra 
    //   Garcia, Hugo 
    //M 
    //   Mortensen, Sven 
    //O 
    //   Omelchenko, Svetlana 
    //   O'Donnell, Claire 
    //T 
    //   Tucker, Lance 
    //   Tucker, Michael 
    //Z 
    //   Zabokritski, Eugene
    

    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);
    }
    
    // Output: 
    // Omelchenko Svetlana 
    // O'Donnell Claire 
    // Mortensen Sven 
    // Garcia Cesar 
    // Fakhouri Fadi 
    // Feng Hanying 
    // Garcia Hugo 
    // Adams Terry 
    // Zabokritski Eugene 
    // Tucker Michael
    

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

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

  • Come descritto in Sintassi di query e sintassi di metodi in LINQ (C#), 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);
    
    // Output: 
    // Class average score = 334.166666666667
    

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);
    }
    
    // Output: 
    // The Garcias in the class are: 
    // Cesar 
    // Debra 
    // Hugo
    
  2. Il codice precedente in questa procedura dettagliata indica che il punteggio medio della classe è pari a circa 334. Per produrre una sequenza di Students il cui punteggio totale sia superiore alla media della classe, insieme al relativo 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);
    }
    
    // Output: 
    // Student ID: 113, Score: 338 
    // Student ID: 114, Score: 353 
    // Student ID: 116, Score: 369 
    // Student ID: 117, Score: 352 
    // Student ID: 118, Score: 343 
    // Student ID: 120, Score: 341 
    // Student ID: 122, Score: 368
    

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 SQL]

LINQ to DataSet

LINQ to XML

LINQ to Objects

Vedere anche

Attività

Procedura dettagliata: scrittura delle query in Visual Basic

Concetti

Espressioni di query LINQ (Guida per programmatori C#)

Risorse LINQ supplementari

Altre risorse

LINQ (Language-Integrated Query)

Nozioni di base su LINQ in C#