Перейти к основному содержимому

Справочник по LINQ


Назначение

Это полный API-справочник по System.Linq для практики на C# и .NET. Он собран в формате "что есть в библиотеке и как применять без ловушек".

Для пошагового обучения сначала откройте LINQ — язык интегрированных запросов. Для работы с БД через EF Core полезны работа с БД и ORM и EF Core — первая программа.


Ключевые классы LINQ — подробно

Enumerable

Enumerable — главный статический класс LINQ to Objects. Он работает с IEnumerable<T> и выполняет операции в памяти процесса.

  • принимает делегаты Func<...>
  • строит цепочки операторов через yield-итераторы
  • большинство операторов выполняет отложенно
  • материализация начинается на ToList, ToArray, Count, First и других терминальных методах

Пример:

var adults = people
.Where(p => p.Age >= 18)
.OrderBy(p => p.LastName)
.Select(p => p.FullName);

Queryable

Queryable — аналог Enumerable для IQueryable<T>. Он не исполняет запрос сам, а формирует дерево выражений Expression<Func<...>>, которое анализирует провайдер.

  • используется с EF Core, LINQ to DB, OData-провайдерами и другими источниками
  • может переводить выражения в SQL, HTTP-запросы, DSL конкретной БД
  • часть выражений может не поддерживаться конкретным провайдером

Пример:

var query = db.Users
.Where(u => u.IsActive)
.Select(u => new { u.Id, u.Email });

ParallelEnumerable

ParallelEnumerable — API PLINQ для ParallelQuery<T>. Он разделяет последовательность на партиции и выполняет обработку на нескольких потоках.

  • оптимален для CPU-bound вычислений
  • даёт выигрыш на больших объёмах
  • порядок результата нужно явно сохранять через AsOrdered
  • побочные эффекты в Select и Where создают гонки данных

EnumerableQuery<T>

EnumerableQuery<T> — адаптер, который представляет обычную IEnumerable<T> как IQueryable<T>. Нужен для сценариев, где API ожидает IQueryable.

Практический смысл:

  • запрос по факту всё равно выполняется локально
  • полезно в тестах, универсальных репозиториях и метапрограммировании

Lookup<TKey, TElement>

Lookup<TKey, TElement> — материализованная группировка "ключ → коллекция элементов". Обычно создаётся через ToLookup.

Отличия от Dictionary<TKey, List<T>>:

  • для отсутствующего ключа возвращает пустую коллекцию, а не исключение
  • неизменяем после построения
  • один ключ естественно связан со множеством значений

Полный API Enumerable — с раскрытием

Фильтрация

  • Where — оставить элементы, где предикат возвращает true.
  • OfType — отфильтровать элементы по типу и привести к нему.
  • Cast — привести каждый элемент к типу, кидает исключение при несовместимости.
  • Take — взять первые n элементов.
  • Skip — пропустить первые n элементов.
  • TakeWhile — брать, пока условие истинно.
  • SkipWhile — пропускать, пока условие истинно.
  • TakeLast — взять последние n элементов.
  • SkipLast — пропустить последние n элементов.

Проекция

  • Select — преобразовать каждый элемент в новый тип.
  • SelectMany — развернуть вложенные коллекции в один поток.

Сортировка

  • OrderBy — первичная сортировка по возрастанию.
  • OrderByDescending — первичная сортировка по убыванию.
  • ThenBy — вторичный ключ сортировки по возрастанию.
  • ThenByDescending — вторичный ключ сортировки по убыванию.
  • Reverse — инвертировать текущий порядок элементов.

Операции над множествами

  • Distinct — убрать дубликаты целых элементов.
  • DistinctBy — убрать дубликаты по ключу.
  • Union — объединить без повторов.
  • UnionBy — объединить без повторов по ключу.
  • Intersect — оставить пересечение двух последовательностей.
  • IntersectBy — пересечение по ключу.
  • Except — оставить элементы первой, которых нет во второй.
  • ExceptBy — разность по ключу.
  • Concat — склеить две последовательности с сохранением всех элементов.
  • Append — добавить один элемент в конец.
  • Prepend — добавить один элемент в начало.

Элементные операторы

  • First — первый элемент, исключение если пусто.
  • FirstOrDefault — первый или default.
  • Last — последний элемент, исключение если пусто.
  • LastOrDefault — последний или default.
  • Single — ровно один элемент, исключение если 0 или больше 1.
  • SingleOrDefault — один или default, исключение если больше 1.
  • ElementAt — элемент по индексу, исключение при выходе за границы.
  • ElementAtOrDefault — элемент по индексу или default.
  • DefaultIfEmpty — подставить значение по умолчанию, если последовательность пуста.

Квантификаторы и проверки

  • Any — существует хотя бы один элемент или хотя бы один по условию.
  • All — все элементы удовлетворяют условию.
  • Contains — есть ли конкретное значение.
  • SequenceEqual — совпадают ли две последовательности поэлементно.

Агрегация

  • Aggregate — свёртка последовательности пользовательской функцией.
  • Count — количество элементов (int).
  • LongCount — количество элементов (long).
  • Sum — сумма чисел или проекции.
  • Average — среднее значение.
  • Min — минимальное значение.
  • Max — максимальное значение.
  • MinBy — элемент с минимальным ключом.
  • MaxBy — элемент с максимальным ключом.

Группировка и индексирование

  • GroupBy — разбить элементы на группы по ключу.
  • ToLookup — немедленно построить индекс группировок.

Соединения

  • Join — внутреннее соединение по ключу.
  • GroupJoin — группированное соединение, база для левого соединения.

Генерация

  • Empty — пустая последовательность.
  • Range — диапазон целых чисел.
  • Repeat — повторить значение n раз.
  • Chunk — разбить на чанки фиксированного размера.
  • Zip — попарно объединить две последовательности.

Материализация и конвертация

  • ToArray — выполнить и вернуть массив.
  • ToList — выполнить и вернуть список.
  • ToDictionary — выполнить и собрать словарь.
  • ToHashSet — выполнить и собрать множество.
  • ToLookup — выполнить и собрать индексированный набор групп.
  • ToImmutableArray — собрать неизменяемый массив.
  • AsEnumerable — зафиксировать дальнейшие операции как LINQ to Objects.
  • AsQueryable — представить последовательность как IQueryable.

Queryable — чем отличается каждый оператор

По названиям методы те же, что в Enumerable. Разница в контракте:

  • Where, Select, OrderBy и другие принимают Expression<Func<...>>
  • провайдер читает дерево выражения, а не исполняемый делегат
  • итог выполнения зависит от того, какие конструкции умеет переводить конкретный провайдер

Что важно на практике:

  • .AsEnumerable() после IQueryable переносит продолжение цепочки в память
  • пользовательские C#-методы внутри Where часто не транслируются в SQL
  • GroupBy лучше сразу завершать проекцией с агрегатами

ParallelEnumerable и PLINQ — зачем и как

Ключевые методы управления выполнением:

  • AsParallel — старт параллельного пайплайна
  • AsSequential — вернуть обычный последовательный режим
  • AsOrdered / AsUnordered — сохранить или снять требование порядка
  • WithDegreeOfParallelism — ограничить число потоков
  • WithExecutionMode — дать подсказку принудительной параллелизации
  • WithMergeOptions — управлять слиянием результатов
  • WithCancellation — поддержать отмену токеном
  • ForAll — применить действие к каждому элементу без обратной сборки

Операторы обработки и агрегирования (Where, Select, GroupBy, Count, Sum и другие) работают аналогично Enumerable, но в многопоточном режиме.


IAsyncEnumerable<T> и LINQ для async

Базовые типы:

  • IAsyncEnumerable<T> — асинхронная последовательность
  • IAsyncEnumerator<T> — асинхронный перечислитель
  • await foreach — синтаксис перебора
  • WithCancellation — проброс токена отмены

Через пакет System.Linq.Async добавляются операторы:

  • SelectAwait, WhereAwait, SelectManyAwait
  • ToListAsync, ToArrayAsync, ToDictionaryAsync
  • FirstOrDefaultAsync, SingleOrDefaultAsync, AnyAsync, AllAsync, CountAsync
  • SumAsync, AverageAsync, MinAsync, MaxAsync

Интерфейсы и специальные типы вокруг LINQ

Интерфейсы

  • IEnumerable<T> — последовательность для синхронного перебора.
  • IEnumerator<T> — объект состояния перебора (MoveNext, Current).
  • IQueryable<T> — запрос, который можно разобрать как выражение.
  • IQueryProvider — движок, который создаёт и исполняет IQueryable.
  • IGrouping<TKey, TElement> — одна группа из GroupBy.
  • ILookup<TKey, TElement> — индекс ключа в коллекции значений.
  • IOrderedEnumerable<T> — маркер отсортированного результата LINQ to Objects.
  • IOrderedQueryable<T> — маркер отсортированного результата LINQ-провайдера.

Вспомогательные типы

  • Lookup<TKey, TElement> — реализация ILookup.
  • EnumerableQuery<T> — адаптер IEnumerable к IQueryable.
  • ParallelQuery<T> — базовый тип последовательности PLINQ.
  • OrderedParallelQuery<T> — отсортированный ParallelQuery.

Важные сигнатуры

Ниже сигнатуры, которые чаще всего определяют поведение:

Код ITЗагрузка примера кода…


Что выполняется отложенно

Почти все операторы, возвращающие последовательность, выполняются отложенно:

  • Where, Select, SelectMany
  • OrderBy, ThenBy
  • GroupBy, Join, GroupJoin
  • Distinct, Union, Intersect, Except
  • Take, Skip, TakeWhile, SkipWhile

Немедленное выполнение дают:

  • ToList, ToArray, ToDictionary, ToHashSet
  • Count, LongCount, Any, All, Contains
  • First, Single, Last
  • Sum, Average, Min, Max, Aggregate

Ограничения и ловушки

  • AsEnumerable останавливает трансляцию IQueryable в SQL и переключает исполнение на клиент.
  • AsQueryable над обычной коллекцией не делает провайдер БД, это обертка для LINQ to Objects.
  • Last() для SQL-сценария почти всегда заменяют на OrderByDescending(...).FirstOrDefault().
  • Повторное перечисление запроса без материализации запускает повторное выполнение.
  • Для GroupBy в EF Core нужен явный Select с агрегатами, чтобы получить чистый SQL GROUP BY.

Быстрые паттерны

Безопасный запрос к БД

var page = await db.Orders
.AsNoTracking()
.Where(o => o.CreatedAt >= fromDate)
.OrderBy(o => o.Id)
.Skip(page * size)
.Take(size)
.Select(o => new { o.Id, o.Total })
.ToListAsync();

Левое соединение

var leftJoin = users
.GroupJoin(orders, u => u.Id, o => o.UserId, (u, os) => new { u, os })
.SelectMany(x => x.os.DefaultIfEmpty(), (x, o) => new { x.u.Name, OrderId = o?.Id });

Пакетная обработка

foreach (var chunk in items.Chunk(500))
{
await ProcessChunkAsync(chunk);
}

Официальные ссылки API



В подборках

Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:

СправочникиСправочник по конфигурациям в C#, Справочник по ASP.NET, Справочник по F#, Справочник по C#, Документация и инструменты Java (Microsoft), Справочник по C++.