Справочник по 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,SelectManyAwaitToListAsync,ToArrayAsync,ToDictionaryAsyncFirstOrDefaultAsync,SingleOrDefaultAsync,AnyAsync,AllAsync,CountAsyncSumAsync,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,SelectManyOrderBy,ThenByGroupBy,Join,GroupJoinDistinct,Union,Intersect,ExceptTake,Skip,TakeWhile,SkipWhile
Немедленное выполнение дают:
ToList,ToArray,ToDictionary,ToHashSetCount,LongCount,Any,All,ContainsFirst,Single,LastSum,Average,Min,Max,Aggregate
Ограничения и ловушки
AsEnumerableостанавливает трансляциюIQueryableв SQL и переключает исполнение на клиент.AsQueryableнад обычной коллекцией не делает провайдер БД, это обертка для LINQ to Objects.Last()для SQL-сценария почти всегда заменяют наOrderByDescending(...).FirstOrDefault().- Повторное перечисление запроса без материализации запускает повторное выполнение.
- Для
GroupByв EF Core нужен явныйSelectс агрегатами, чтобы получить чистый SQLGROUP 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++.