← Назад к вопросам

Какой тип возвращает Where?

1.6 Junior🔥 231 комментариев
#C# и ООП#Коллекции и структуры данных

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Возвращаемый тип метода Where в LINQ (C#)

В C# метод Where является стандартным методом расширения LINQ (Language Integrated Query) и возвращает IEnumerable<T> (или его обобщенную вариацию) для последовательностей в памяти (например, коллекций) или IQueryable<T> для запросов к источникам данных с отложенным выполнением (например, базам данных через Entity Framework).

Ключевые особенности возвращаемого типа

  • Отложенное выполнение (Deferred Execution): Метод Where не выполняет фильтрацию сразу в момент вызова. Вместо этого он возвращает объект-перечислитель, который содержит логику фильтрации и будет выполнен только при итерации (например, в цикле foreach) или при вызове методов, требующих материализации результата (ToList, ToArray, First).
  • Обобщенный интерфейс: Конкретный тип зависит от типа исходной последовательности и способа вызова. Он всегда является производным от IEnumerable<T> или IQueryable<T>.

Примеры кода и возвращаемые типы

1. Работа с коллекциями в памяти (возвращает IEnumerable<T>)

using System;
using System.Collections.Generic;
using System.Linq;

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

// Возвращаемый тип: IEnumerable<int>
IEnumerable<int> evenNumbersQuery = numbers.Where(n => n % 2 == 0);
Console.WriteLine(evenNumbersQuery.GetType().Name); // WhereListIterator`1

// Материализация отложенного запроса в список
List<int> evenNumbersList = evenNumbersQuery.ToList(); // Теперь тип List<int>

// Итерация вызывает выполнение фильтрации
foreach (var num in evenNumbersQuery)
{
    Console.Write(num + " "); // 2 4 6
}

2. Работа с запросами к базам данных (возвращает IQueryable<T>)

using System.Linq;
using (var context = new MyDbContext())
{
    // IQueryable<Customer> - запрос еще не выполнен на сервере
    IQueryable<Customer> activeCustomersQuery = context.Customers
        .Where(c => c.IsActive);

    // Запрос будет выполнен только здесь (при вызове ToList)
    List<Customer> activeCustomersList = activeCustomersQuery.ToList();
}

Тип IQueryable<T> позволяет строить динамические запросы, которые транслируются в SQL (или другой язык запросов) и выполняются на стороне источника данных.

Варианты перегрузок и типов

  • Для IEnumerable<T>: Метод Where возвращает IEnumerable<T>.
  • Для IQueryable<T>: Метод Where возвращает IQueryable<T>.
  • Перегрузка с индексом: Существует перегрузка Where((item, index) => ...), которая также возвращает IEnumerable<T> или IQueryable<T>, но позволяет использовать индекс элемента в предикате.
string[] fruits = { "apple", "banana", "cherry", "date" };
// Использование индекса в предикате
IEnumerable<string> longFruits = fruits.Where((fruit, index) => fruit.Length > index);

Заключение

Таким образом, метод Where всегда возвращает один из обобщенных интерфейсов IEnumerable<T> или IQueryable<T>, представляющий отложенный запрос на фильтрацию. Конкретный тип определяется контекстом вызова: для массивов, списков и других коллекций в памяти — это обычно реализации IEnumerable<T> (например, WhereListIterator), а для запросов к внешним источникам данных через LINQ-провайдеры (как Entity Framework) — IQueryable<T>. Это позволяет строить эффективные цепочки запросов и выполнять их однократно в оптимальный момент.