Запрос коллекции объектов
Термин "LINQ to Objects" означает использование запросов LINQ с любой коллекцией IEnumerable или IEnumerable<T> напрямую, без привлечения промежуточного поставщика LINQ, API LINQ to SQL или LINQ to XML. Вы можете выполнить запрос LINQ к любой перечислимой коллекции, такой как List<T>, Array или Dictionary<TKey,TValue>. Коллекция может быть определена пользователем или возвращена API .NET. При использовании LINQ пишется декларативный код, описывающий, какие данные необходимо извлечь.
Кроме того, запросы LINQ предлагают три основных преимущества по сравнению с традиционными циклами foreach
:
- Они более краткие и удобочитаемые, особенно при фильтрации нескольких условий.
- Они предоставляют широкие возможности фильтрации, упорядочивания и группировки с минимумом кода приложения.
- Они могут переноситься в другие источники данных практически без изменений.
В общем, чем сложнее операция, которую нужно выполнить с данными, тем больше преимуществ вы получаете при использовании LINQ вместо традиционных способов итерации.
В этом примере показано, как выполнить простой запрос к списку объектов Student
. Каждый объект Student
содержит некоторые основные сведения об учащемся, а также список, отражающий баллы, которые он набрал по результатам четырех экзаменов.
Примечание.
Многие другие примеры в этом разделе используют тот же Student
класс и students
коллекцию.
class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
public GradeLevel? Year { get; set; }
public List<int> ExamScores { get; set; }
public Student(string FirstName, string LastName, int ID, GradeLevel Year, List<int> ExamScores)
{
this.FirstName = FirstName;
this.LastName = LastName;
this.ID = ID;
this.Year = Year;
this.ExamScores = ExamScores;
}
public Student(string FirstName, string LastName, int StudentID, List<int>? ExamScores = null)
{
this.FirstName = FirstName;
this.LastName = LastName;
ID = StudentID;
this.ExamScores = ExamScores ?? [];
}
public static List<Student> students =
[
new(
FirstName: "Terry", LastName: "Adams", ID: 120,
Year: GradeLevel.SecondYear,
ExamScores: [99, 82, 81, 79]
),
new(
"Fadi", "Fakhouri", 116,
GradeLevel.ThirdYear,
[99, 86, 90, 94]
),
new(
"Hanying", "Feng", 117,
GradeLevel.FirstYear,
[93, 92, 80, 87]
),
new(
"Cesar", "Garcia", 114,
GradeLevel.FourthYear,
[97, 89, 85, 82]
),
new(
"Debra", "Garcia", 115,
GradeLevel.ThirdYear,
[35, 72, 91, 70]
),
new(
"Hugo", "Garcia", 118,
GradeLevel.SecondYear,
[92, 90, 83, 78]
),
new(
"Sven", "Mortensen", 113,
GradeLevel.FirstYear,
[88, 94, 65, 91]
),
new(
"Claire", "O'Donnell", 112,
GradeLevel.FourthYear,
[75, 84, 91, 39]
),
new(
"Svetlana", "Omelchenko", 111,
GradeLevel.SecondYear,
[97, 92, 81, 60]
),
new(
"Lance", "Tucker", 119,
GradeLevel.ThirdYear,
[68, 79, 88, 92]
),
new(
"Michael", "Tucker", 122,
GradeLevel.FirstYear,
[94, 92, 91, 91]
),
new(
"Eugene", "Zabokritski", 121,
GradeLevel.FourthYear,
[96, 85, 91, 60]
)
];
}
enum GradeLevel
{
FirstYear = 1,
SecondYear,
ThirdYear,
FourthYear
};
Пример
Следующий запрос возвращает список учащихся, набравших 90 баллов или больше на первом экзамене.
void QueryHighScores(int exam, int score)
{
var highScores =
from student in students
where student.ExamScores[exam] > score
select new
{
Name = student.FirstName,
Score = student.ExamScores[exam]
};
foreach (var item in highScores)
{
Console.WriteLine($"{item.Name,-15}{item.Score}");
}
}
QueryHighScores(0, 90);
Этот запрос намеренно сделан простым, чтобы с ним можно было экспериментировать. Например, можно добавить в предложение where
дополнительные условия или отсортировать результаты с помощью предложения orderby
.
Классификация стандартных операторов запросов по способу выполнения
В реализации LINQ to Objects выполнение методов стандартных операторов запросов бывает немедленным и отложенным. Операторы запросов, использующие отложенное выполнение, можно дополнительно разделить на две категории: потоковые и непотоковые. Если вы знаете, каким образом выполняются разные операторы запросов, это может помочь понять результаты, полученные из данного запроса. Это особенно справедливо при изменении источника данных или создании одного запроса поверх другого. В этом разделе представлена классификация стандартных операторов запросов по способу выполнения.
Интерпретация
Немедленное выполнение означает, что источник данных считывается и операция выполняется один раз. Все стандартные операторы запросов, возвращающие скалярный результат, выполняются немедленно. Вы можете принудительно выполнить запрос немедленно с помощью Enumerable.ToList или Enumerable.ToArray методов. Немедленное выполнение обеспечивает повторное использование результатов запроса, а не объявление запроса. Результаты извлекаются один раз, а затем хранятся для дальнейшего использования.
Действие отложено
Отложенное выполнение означает, что операция не выполняется в той точке кода, где объявлен запрос. Она выполняется только после перечисления переменной запроса, например с помощью оператора foreach
. Это означает, что результаты выполнения запроса зависят от содержимого источника данных при выполнении запроса, а не при его определении. Если переменная запроса перечисляется несколько раз, результаты могут каждый раз отличаться. Практически все стандартные операторы запроса, которые возвращают значения типа IEnumerable<T> или IOrderedEnumerable<TElement>, выполняются отложенным способом. Отложенное выполнение обеспечивает повторное использование запроса, так как запрос получает обновленные данные из источника данных при каждом итерации результатов запроса.
Операторы запросов, использующие отложенное выполнение, можно дополнительно разделить на потоковые и непотоковые.
Потоковая передача
Потоковые операторы не считывают все исходные данные до создания элементов. Во время выполнения потоковый оператор выполняет свою операцию с каждым исходным элементом по мере считывания и при необходимости создает элемент. Потоковый оператор продолжает считывание исходных элементов до того момента, когда можно будет создать итоговый элемент. Это означает, что для получения одного итогового элемента может быть считано несколько исходных элементов.
Не используют потоковую передачу.
Непотоковые операторы должны считать все исходные данные до создания итогового элемента. В эту категорию попадают операции сортировки и группировки. Во время выполнения непотоковые операторы запросов считывают все исходные данные, помещают их в структуру данных, выполняют операцию и создают итоговые элементы.
Таблица классификации
В следующей таблице приведена классификация всех методов стандартных операторов запросов по способу выполнения.
Примечание.
Если оператор помечен в двух столбцах, в операции участвуют две входные последовательности, и каждая последовательность вычисляется по-разному. В таких случаях первая последовательность в списке параметров всегда вычисляется отложенным потоковым способом.
См. также
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделе:Отправить и просмотреть отзыв по