Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym samouczku utworzysz źródło danych i napiszesz kilka zapytań LINQ. Możesz eksperymentować z wyrażeniami zapytań i zobaczyć różnice w wynikach. W tym przewodniku przedstawiono funkcje języka C#, które są używane do pisania wyrażeń zapytań LINQ. Możesz samodzielnie śledzić i kompilować aplikację oraz eksperymentować z zapytaniami. W tym artykule założono, że zainstalowano najnowszy zestaw .NET SDK. Jeśli nie, przejdź do strony Pliki do pobrania platformy .NET i zainstaluj najnowszą wersję na maszynie.
Najpierw utwórz aplikację. W konsoli wpisz następujące polecenie:
dotnet new console -o WalkthroughWritingLinqQueries
Jeśli wolisz program Visual Studio, utwórz nową aplikację konsolową o nazwie WalkthroughWritingLinqQueries.
Tworzenie źródła danych w pamięci
Pierwszym krokiem jest utworzenie źródła danych dla zapytań. Źródło danych dla zapytań to prosta lista rekordów Student . Każdy Student rekord ma imię, nazwę rodziny i tablicę liczb całkowitych reprezentujących wyniki testów w klasie. Dodaj nowy plik o nazwie students.cs i skopiuj następujący kod do tego pliku:
namespace WalkthroughWritingLinqQueries;
public record Student(string First, string Last, int ID, int[] Scores);
Zwróć uwagę na następujące cechy:
- Rekord
Studentskłada się z automatycznie zaimplementowanych właściwości. - Każdy uczeń na liście jest inicjowany przy użyciu konstruktora podstawowego.
- Sekwencja wyników dla każdego ucznia jest inicjowana przy użyciu konstruktora podstawowego.
Następnie utwórz sekwencję rekordów Student , która służy jako źródło tego zapytania. Otwórz Program.cs i usuń następujący standardowy kod:
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Zastąp go następującym kodem, który tworzy sekwencję rekordów Student :
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])
];
- Sekwencja uczniów jest inicjowana za pomocą wyrażenia zbioru.
- Typ
Studentrekordu zawiera statyczną listę wszystkich uczniów. - Niektóre wywołania konstruktora używają nazwanych argumentów , aby wyjaśnić, który argument pasuje do parametru konstruktora.
Spróbuj dodać kilku kolejnych uczniów z różnymi wynikami testu do listy uczniów, aby lepiej zapoznać się z kodem, nad którym pracujesz.
Tworzenie zapytania
Następnie utworzysz pierwsze zapytanie. W wyniku wykonania zapytania zostanie utworzona lista wszystkich uczniów, których wynik w pierwszym teście był większy niż 90. Ponieważ zaznaczono cały Student obiekt, typ zapytania to IEnumerable<Student>. Mimo że kod może również używać niejawnego typowania przy użyciu słowa kluczowego var, jawne typowanie służy do jasnego zilustrowania wyników. (Aby uzyskać więcej informacji na temat var, zobacz Niejawnie wpisane zmienne lokalne.) Dodaj następujący kod do Program.cs, po kodzie, który tworzy sekwencję uczniów:
// 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;
Zmienna zakresu zapytania student służy jako odwołanie do każdego Student w źródle, zapewniając dostęp do składowych każdego obiektu.
Uruchamianie zapytania
Teraz napisz pętlę foreach , która powoduje wykonanie zapytania. Dostęp do każdego elementu w zwróconej sekwencji jest uzyskiwany za pośrednictwem zmiennej foreach iteracji w pętli. Typ tej zmiennej to Student, a typ zmiennej kwerendy jest zgodny, IEnumerable<Student>. Po dodaniu następującego kodu skompiluj i uruchom aplikację, aby wyświetlić wyniki w oknie Konsola .
// 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
Aby dokładniej uściślić zapytanie, możesz połączyć wiele warunków logicznych w klauzuli where . Poniższy kod dodaje warunek, tak aby zapytanie zwróciło tych uczniów, których pierwszy wynik wynosił ponad 90 i którego ostatni wynik był mniejszy niż 80. Klauzula where powinna przypominać następujący kod.
where student.Scores[0] > 90 && student.Scores[3] < 80
Wypróbuj poprzednią where klauzulę lub poeksperymentuj samodzielnie z innymi warunkami filtrowania. Aby uzyskać więcej informacji, zobacz klauzulę , w której.
Zamawianie wyników zapytania
Łatwiej jest skanować wyniki, jeśli są w jakiejś kolejności. Zwróconą sekwencję można uporządkować według dowolnego dostępnego pola w elementach źródłowych. Na przykład poniższa orderby klauzula porządkuje wyniki w kolejności alfabetycznej od A do Z zgodnie z nazwą rodziny każdego ucznia. Dodaj następującą orderby klauzulę do zapytania bezpośrednio po instrukcji where i przed instrukcją select :
orderby student.Last ascending
Teraz zmień klauzulę orderby tak, aby porządkowała wyniki w odwrotnej kolejności zgodnie z wynikiem w pierwszym teście, od najwyższego wyniku do najniższego wyniku.
orderby student.Scores[0] descending
WriteLine Zmień ciąg formatu, aby zobaczyć wyniki:
Console.WriteLine($"{student.Last}, {student.First} {student.Scores[0]}");
Aby uzyskać więcej informacji, zobacz klauzulę ORDER BY
Grupuj wyniki
Grupowanie to zaawansowana funkcja w wyrażeniach zapytań. Zapytanie z klauzulą grupy tworzy sekwencję grup, a każda grupa zawiera Key oraz sekwencję składającą się ze wszystkich członków tej grupy. Następujące nowe zapytanie grupuje uczniów przy użyciu pierwszej litery swojego nazwiska rodzinnego jako klucza.
IEnumerable<IGrouping<char, Student>> studentQuery =
from student in students
group student by student.Last[0];
Typ zapytania został zmieniony. Teraz tworzy sekwencję grup, które mają char typ jako klucz i sekwencję Student obiektów. Kod w foreach pętli wykonywania musi również ulec zmianie:
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
Uruchom aplikację i wyświetl wyniki w oknie Konsola . Aby uzyskać więcej informacji, zobacz klauzulę grupy.
Jawne kodowanie IEnumerables z IGroupings może szybko stać się żmudne. Napisz to samo zapytanie i foreach pętlę w sposób znacznie wygodniejszy przy użyciu var. Słowo var kluczowe nie zmienia typów obiektów— po prostu nakazuje kompilatorowi wnioskowanie typów. Zmień typ zmiennej studentQuery i iteracji group na var i uruchom ponownie zapytanie. W pętli wewnętrznej foreach zmienna iteracji jest nadal wpisywana jako Student, a zapytanie działa tak jak poprzednio. Zmień zmienną student iteracji na var i ponownie uruchom zapytanie. Zobaczysz, że uzyskasz dokładnie te same wyniki.
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}");
}
}
Aby uzyskać więcej informacji na temat var, zobacz Niejawnie typizowane zmienne lokalne.
Porządkowanie grup według ich wartości klucza
Grupy w poprzednim zapytaniu nie są w kolejności alfabetycznej. Klauzulę orderby można podać po klauzuli group . Jednak aby użyć orderby klauzuli, najpierw potrzebujesz identyfikatora, który służy jako odwołanie do grup utworzonych przez klauzulę group . Identyfikator należy podać przy użyciu słowa kluczowego into w następujący sposób:
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
Uruchom to zapytanie, a grupy są teraz sortowane w kolejności alfabetycznej.
Możesz użyć słowa kluczowego let, żeby wprowadzić identyfikator dla dowolnego wyniku wyrażenia w wyrażeniu zapytania. Ten identyfikator może być wygodą, jak w poniższym przykładzie. Może również zwiększyć wydajność, przechowując wyniki wyrażenia, aby nie trzeba było ich wielokrotnie obliczać.
// 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
Aby uzyskać więcej informacji, zobacz artykuł na temat klauzulilet .
Używanie składni metody w wyrażeniu zapytania
Zgodnie z opisem w artykule Składnia zapytań i składnia metody w LINQ niektóre operacje zapytań można wyrazić tylko przy użyciu składni metody. Poniższy kod oblicza łączny wynik dla każdej Student w sekwencji źródłowej, a następnie wywołuje metodę Average() na wynikach tego zapytania, aby obliczyć średni wynik klasy.
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
Aby przekształcić lub rzutować w klauzuli select
Często zapytanie tworzy sekwencję, której elementy różnią się od elementów w sekwencjach źródłowych. Usuń lub oznacz jako komentarz swoje poprzednie zapytanie i pętlę wykonawczą, a następnie zastąp je następującym kodem. Zapytanie zwraca sekwencję ciągów (nie Students), a ten fakt jest odzwierciedlany w foreach pętli.
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
Jak wskazano wcześniej w tym przewodniku, kod pokazał, że średni wynik klasy wynosi około 334. Aby utworzyć sekwencję Students, której łączna ocena jest większa niż średnia klasy, wraz z ich Student ID, można użyć typu anonimowego w instrukcji 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