Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Neste tutorial, você cria uma fonte de dados e escreve várias consultas LINQ. Você pode experimentar as expressões de consulta e ver as diferenças nos resultados. Este passo a passo demonstra os recursos da linguagem C# que são usados para escrever expressões de consulta LINQ. Você pode acompanhar e criar o aplicativo e experimentar as consultas por conta própria. Este artigo pressupõe que você tenha instalado o SDK .NET mais recente. Caso contrário, vá para a página Downloads do .NET e instale a versão mais recente em sua máquina.
Primeiro, crie o aplicativo. No console, digite o seguinte comando:
dotnet new console -o WalkthroughWritingLinqQueries
Ou, se preferir o Visual Studio, crie um novo aplicativo de console chamado WalkthroughWritingLinqQueries.
Criar uma fonte de dados na memória
A primeira etapa é criar uma fonte de dados para suas consultas. A fonte de dados para as consultas é uma lista simples de Student
registros. Cada Student
registro tem um nome, nome de família e uma matriz de inteiros que representa suas pontuações de teste na classe. Adicione um novo arquivo chamado students.cs e copie o seguinte código para esse arquivo:
namespace WalkthroughWritingLinqQueries;
public record Student(string First, string Last, int ID, int[] Scores);
Observe as seguintes características:
- O
Student
registro consiste em propriedades implementadas automaticamente. - Cada aluno na lista é inicializado com o construtor primário.
- A sequência de pontuações para cada aluno é inicializada com um construtor primário.
Em seguida, crie uma sequência de Student
registros que sirva como fonte dessa consulta. Abra Program.cs e remova o seguinte código clichê:
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Substitua-o pelo seguinte código que cria uma sequência de Student
registros:
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])
];
- A sequência de estudantes é inicializada com uma expressão de coleção.
- O
Student
tipo de registro contém a lista estática de todos os alunos. - Algumas das chamadas do construtor usam argumentos nomeados para esclarecer qual argumento corresponde a qual parâmetro do construtor.
Tente adicionar mais alguns alunos com pontuações de teste diferentes à lista de alunos para se familiarizar mais com o código até agora.
Criar a consulta
Em seguida, crie sua primeira consulta. A sua consulta, quando a executa, produz uma lista de todos os alunos cuja pontuação no primeiro teste foi superior a 90. Como todo o Student
objeto está selecionado, o tipo da consulta é IEnumerable<Student>
. Embora o código também possa usar a digitação implícita usando a palavra-chave var , a digitação explícita é usada para ilustrar claramente os resultados. (Para informações adicionais sobre var
, consulte Variáveis locais digitadas implicitamente.) Adicione o seguinte código ao Program.cs, após o código que cria a sequência de alunos.
// 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;
A variável de intervalo da consulta, student
, serve como referência para cada Student
um na fonte, fornecendo acesso de membro para cada objeto.
Executar a consulta
Agora escreva o foreach
loop que faz com que a consulta seja executada. Cada elemento na sequência retornada é acessado através da variável de iteração no foreach
loop. O tipo desta variável é Student
, e o tipo da variável de consulta é compatível, IEnumerable<Student>
. Depois de adicionar o código a seguir, compile e execute o aplicativo para ver os resultados na janela 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
Para refinar ainda mais a consulta, você pode combinar várias condições booleanas where
na cláusula. O código a seguir adiciona uma condição para que a consulta retorne os alunos cuja primeira pontuação foi superior a 90 e cuja última pontuação foi inferior a 80. A where
cláusula deve assemelhar-se ao código seguinte.
where student.Scores[0] > 90 && student.Scores[3] < 80
Experimente a cláusula anterior where
ou experimente outras condições de filtro. Para obter mais informações, consulte cláusula WHERE.
Ordenar os resultados da consulta
É mais fácil digitalizar os resultados se eles estiverem em algum tipo de ordem. Você pode ordenar a sequência retornada por qualquer campo acessível nos elementos de origem. Por exemplo, a cláusula a seguir orderby
ordena os resultados em ordem alfabética de A a Z de acordo com o nome de família de cada aluno. Adicione a seguinte orderby
cláusula à sua consulta, logo após a where
instrução e antes da select
instrução:
orderby student.Last ascending
Agora altere a orderby
cláusula para que ela ordene os resultados em ordem inversa de acordo com a pontuação no primeiro teste, da maior pontuação para a menor pontuação.
orderby student.Scores[0] descending
Altere a cadeia de caracteres de WriteLine
formato para que você possa ver as pontuações:
Console.WriteLine($"{student.Last}, {student.First} {student.Scores[0]}");
Para obter mais informações, consulte a cláusula de ordenação por .
Agrupar os resultados
O agrupamento é um recurso poderoso em expressões de consulta. Uma consulta com uma cláusula de grupo produz uma sequência de grupos, e cada grupo em si contém uma Key
e uma sequência que consiste em todos os membros desse grupo. A nova consulta a seguir agrupa os alunos usando a primeira letra do nome da família como chave.
IEnumerable<IGrouping<char, Student>> studentQuery =
from student in students
group student by student.Last[0];
O tipo da consulta foi alterado. Ele agora produz uma sequência de grupos que têm um char
tipo como chave e uma sequência de Student
objetos. O código no loop de execução foreach
também deve mudar.
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
Execute o aplicativo e visualize os resultados na janela Console . Para obter mais informações, consulte o grupo de cláusulas .
A codificação IEnumerables
explícita de IGroupings
pode rapidamente tornar-se entediante. Escreva a mesma consulta e execute o loop de forma muito mais conveniente usando var
. A var
palavra-chave não altera os tipos de seus objetos, apenas instrui o compilador a inferir os tipos. Altere o tipo de studentQuery
e a variável de iteração group
para var
e execute novamente a consulta. No loop interno foreach
, a variável de iteração ainda é digitada como Student
, e a consulta funciona como antes. Altere a student
variável de iteração para var
e execute a consulta novamente. Você vê que obtém exatamente os mesmos resultados.
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}");
}
}
Para obter mais informações sobre var
, consulte Variáveis locais tipadas implicitamente.
Ordenar os grupos pelo seu valor-chave
Os grupos na consulta anterior não estão em ordem alfabética. Você pode fornecer uma orderby
cláusula após a group
cláusula. Mas para usar uma orderby
cláusula, primeiro você precisa de um identificador que sirva de referência para os grupos criados pela group
cláusula. Você fornece o identificador usando a palavra-chave into
, da seguinte maneira:
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
Execute essa consulta e os grupos agora são classificados em ordem alfabética.
Você pode usar a let
palavra-chave para introduzir um identificador para qualquer resultado de expressão na expressão de consulta. Esse identificador pode ser uma conveniência, como no exemplo a seguir. Ele também pode melhorar o desempenho armazenando os resultados de uma expressão para que ela não precise ser calculada várias vezes.
// 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
Para obter mais informações, consulte o artigo sobre a let
cláusula.
Usar sintaxe de método em uma expressão de consulta
Conforme descrito em Sintaxe de consulta e sintaxe de método no LINQ, algumas operações de consulta só podem ser expressas usando sintaxe de método. O código a seguir calcula a pontuação total de cada Student
na sequência de origem e, em seguida, chama o Average()
método nos resultados dessa consulta para calcular a média de pontuação da 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
Para transformar ou projetar na cláusula de seleção
É comum que uma consulta produza uma sequência cujos elementos diferem dos elementos nas sequências de origem. Exclua ou comente sua consulta anterior e loop de execução e substitua-o pelo código a seguir. A consulta retorna uma sequência de cadeias de caracteres (não Students
), e este facto reflete-se no loop foreach
.
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
O código anterior neste passo a passo indicou que a pontuação média da classe é de aproximadamente 334. Para produzir uma sequência de Students
cuja pontuação total é maior do que a média da classe, juntamente com os seus Student ID
, você pode usar um tipo anônimo na instrução 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