Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In questa esercitazione viene creata un'origine dati e vengono scritte diverse query LINQ. È possibile sperimentare le espressioni di query e visualizzare le differenze nei risultati. Questa procedura dettagliata illustra le funzionalità del linguaggio C# usate per scrivere espressioni di query LINQ. È possibile seguire e compilare l'app ed eseguire l'esperimento con le query manualmente. Questo articolo presuppone che sia stata installata la versione più recente di .NET SDK. In caso contrario, passare alla pagina download .NET e installare la versione più recente nel computer.
Creare prima di tutto l'applicazione. Nella console digitare il comando seguente:
dotnet new console -o WalkthroughWritingLinqQueries
In alternativa, se si preferisce Visual Studio, creare una nuova applicazione console denominata WalkthroughWritingLinqQueries.
Creare un'origine dati in memoria
Il primo passaggio consiste nel creare un'origine dati per le query. L'origine dati per le query è un semplice elenco di Student record. Ogni Student record ha un nome, un nome di famiglia e una matrice di numeri interi che rappresenta i punteggi di test nella classe . Aggiungere un nuovo file denominato students.cs e copiare il codice seguente in tale file:
namespace WalkthroughWritingLinqQueries;
public record Student(string First, string Last, int ID, int[] Scores);
Si notino le caratteristiche seguenti:
- Il
Studentrecord è costituito da proprietà implementate automaticamente. - Ogni studente nell'elenco viene inizializzato con il costruttore primario.
- La sequenza di punteggi per ogni studente viene inizializzata con un costruttore primario.
Creare quindi una sequenza di Student record che funge da origine della query. Aprire Program.cs e rimuovere il codice boilerplate seguente:
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Sostituirlo con il codice seguente che crea una sequenza di Student record:
using WalkthroughWritingLinqQueries;
// Create a data source by using a collection initializer.
IEnumerable<Student> students =
[
new Student(First: "Svetlana", Last: "Omelchenko", ID: 111, Scores: [97, 92, 81, 60]),
new Student(First: "Claire", Last: "O'Donnell", ID: 112, Scores: [75, 84, 91, 39]),
new Student(First: "Sven", Last: "Mortensen", ID: 113, Scores: [88, 94, 65, 91]),
new Student(First: "Cesar", Last: "Garcia", ID: 114, Scores: [97, 89, 85, 82]),
new Student(First: "Debra", Last: "Garcia", ID: 115, Scores: [35, 72, 91, 70]),
new Student(First: "Fadi", Last: "Fakhouri", ID: 116, Scores: [99, 86, 90, 94]),
new Student(First: "Hanying", Last: "Feng", ID: 117, Scores: [93, 92, 80, 87]),
new Student(First: "Hugo", Last: "Garcia", ID: 118, Scores: [92, 90, 83, 78]),
new Student("Lance", "Tucker", 119, [68, 79, 88, 92]),
new Student("Terry", "Adams", 120, [99, 82, 81, 79]),
new Student("Eugene", "Zabokritski", 121, [96, 85, 91, 60]),
new Student("Michael", "Tucker", 122, [94, 92, 91, 91])
];
- La sequenza degli studenti viene inizializzata con un'espressione di raccolta.
- Il
Studenttipo di record contiene l'elenco statico di tutti gli studenti. - Alcune chiamate al costruttore usano argomenti denominati per chiarire quale argomento corrisponde al parametro del costruttore.
Provare ad aggiungere altri studenti con punteggi di test diversi all'elenco degli studenti per acquisire familiarità con il codice finora.
Crea la query
Successivamente, si crea la prima query. La query, quando viene eseguita, genera un elenco di tutti gli studenti il cui punteggio al primo test è maggiore di 90. Poiché l'intero Student oggetto è selezionato, il tipo della query è IEnumerable<Student>. Anche se il codice può anche usare la digitazione implicita usando la parola chiave var , viene usata la digitazione esplicita per illustrare chiaramente i risultati. Per altre informazioni su var, vedere Variabili locali tipizzate in modo implicito. Aggiungere il codice seguente a Program.cs, dopo il codice che crea la sequenza di studenti:
// 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;
La variabile di intervallo della query, student, serve come riferimento per ciascun Student nella fonte, fornendo l'accesso ai membri di ogni oggetto.
Eseguire la query
Ora scrivi il ciclo foreach che provoca l'esecuzione della query. Ogni elemento nella sequenza restituita è accessibile tramite la variabile di iterazione nel foreach ciclo. Il tipo di questa variabile è Studente il tipo della variabile di query è compatibile, IEnumerable<Student>. Dopo aver aggiunto il codice seguente, compilare ed eseguire l'applicazione per visualizzare i risultati nella finestra Console .
// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
Console.WriteLine($"{student.Last}, {student.First}");
}
// Output:
// Omelchenko, Svetlana
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael
Per perfezionare ulteriormente la query, è possibile combinare più condizioni booleane nella where clausola . Il codice seguente aggiunge una condizione in modo che la query restituisca gli studenti il cui primo punteggio è stato superiore a 90 e il cui ultimo punteggio è minore di 80. La where clausola dovrebbe essere simile al codice seguente.
where student.Scores[0] > 90 && student.Scores[3] < 80
Provare la clausola precedente where oppure provare a usare altre condizioni di filtro. Per ulteriori informazioni, vedere la clausola n.di
Ordinare i risultati della query
È più facile analizzare i risultati se sono in qualche tipo di ordine. È possibile ordinare la sequenza restituita da qualsiasi campo accessibile negli elementi di origine. Ad esempio, la clausola seguente orderby ordina i risultati in ordine alfabetico da A a Z in base al nome della famiglia di ogni studente. Aggiungere la clausola seguente orderby alla query subito dopo l'istruzione where e prima dell'istruzione select :
orderby student.Last ascending
Modificare ora la orderby clausola in modo che ordini i risultati in ordine inverso in base al punteggio del primo test, dal punteggio più alto al punteggio più basso.
orderby student.Scores[0] descending
Modifica la stringa di formato WriteLine in modo da poter visualizzare i punteggi:
Console.WriteLine($"{student.Last}, {student.First} {student.Scores[0]}");
Per altre informazioni, vedere clausola orderby.
Raggruppare i risultati
Il raggruppamento è una potente funzionalità nelle espressioni di query. Una query con una clausola group produce una sequenza di gruppi, e ogni gruppo contiene un Key e una sequenza costituita da tutti i membri di quel gruppo. La nuova query seguente raggruppa gli studenti usando la prima lettera del nome della famiglia come chiave.
IEnumerable<IGrouping<char, Student>> studentQuery =
from student in students
group student by student.Last[0];
Il tipo di query è cambiato. Produce ora una sequenza di gruppi con un char tipo come chiave e una sequenza di Student oggetti. Anche il codice del ciclo di esecuzione foreach deve cambiare:
foreach (IGrouping<char, Student> studentGroup in studentQuery)
{
Console.WriteLine(studentGroup.Key);
foreach (Student student in studentGroup)
{
Console.WriteLine($" {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
Eseguire l'applicazione e visualizzare i risultati nella finestra Console . Per ulteriori informazioni, vedere la clausola del gruppo di.
La codifica IEnumerables esplicita di IGroupings può diventare noiosa. Scrivere la stessa query e foreach lo stesso ciclo in modo molto più pratico usando var. La var parola chiave non modifica i tipi degli oggetti. Indica semplicemente al compilatore di dedurre i tipi. Modificare il tipo di studentQuery e la variabile di iterazione group in var e rieseguire nuovamente la query. Nel ciclo interno foreach la variabile di iterazione viene ancora digitata come Studente la query funziona come prima. Modificare la student variabile di iterazione in var ed eseguire di nuovo la query. Si noterà che si ottengono esattamente gli stessi risultati.
IEnumerable<IGrouping<char, Student>> studentQuery =
from student in students
group student by student.Last[0];
foreach (IGrouping<char, Student> studentGroup in studentQuery)
{
Console.WriteLine(studentGroup.Key);
foreach (Student student in studentGroup)
{
Console.WriteLine($" {student.Last}, {student.First}");
}
}
Per altre informazioni su var, vedere Variabili locali tipizzate in modo implicito.
Ordinare i gruppi in base al valore della chiave
I gruppi nella query precedente non sono in ordine alfabetico. È possibile specificare una orderby clausola dopo la group clausola . Tuttavia, per usare una orderby clausola, è necessario innanzitutto un identificatore che funge da riferimento ai gruppi creati dalla group clausola . Specificare l'identificatore usando la into parola chiave , come indicato di seguito:
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($" {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
Esegui questa query e i gruppi sono ordinati in ordine alfabetico ora.
È possibile usare la let parola chiave per introdurre un identificatore per qualsiasi risultato dell'espressione nell'espressione di query. Questo identificatore può essere utile, come nell'esempio seguente. Può anche migliorare le prestazioni archiviando i risultati di un'espressione in modo che non sia necessario calcolare più volte.
// 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 altre informazioni, vedere l'articolo sulla let clausola .
Utilizzare la sintassi del metodo all'interno di un'espressione di query
Come descritto in Sintassi di query e sintassi del metodo in LINQ, alcune operazioni di query possono essere espresse solo usando la sintassi del metodo. Il codice seguente calcola il punteggio totale per ogni Student nella sequenza di origine e quindi chiama il Average() metodo sui risultati della query per calcolare il punteggio medio della classe.
var studentQuery =
from student in students
let totalScore = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
select totalScore;
double averageScore = studentQuery.Average();
Console.WriteLine($"Class average score = {averageScore}");
// Output:
// Class average score = 334.166666666667
Per trasformare o proiettare nella clausola seleziona
È comune che una query producano una sequenza i cui elementi differiscono dagli elementi nelle sequenze di origine. Elimina o commenta la tua query e il ciclo di esecuzione precedenti e sostituiscili con il codice seguente. La query restituisce una sequenza di stringhe (non Students) e questo fatto si riflette nel foreach ciclo.
IEnumerable<string> studentQuery =
from student in students
where student.Last == "Garcia"
select student.First;
Console.WriteLine("The Garcias in the class are:");
foreach (string s in studentQuery)
{
Console.WriteLine(s);
}
// Output:
// The Garcias in the class are:
// Cesar
// Debra
// Hugo
Il codice fornito in precedenza in questa guida indica che il punteggio medio della classe è circa 334. Per produrre una sequenza di Students il cui punteggio totale è maggiore della media della classe, insieme al relativo Student ID, è possibile usare un tipo anonimo nell'istruzione select :
var aboveAverageQuery =
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 aboveAverageQuery)
{
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