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

Что такое интерфейс IEnumerable?

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

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

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

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

Что такое интерфейс IEnumerable?

IEnumerable — это один из фундаментальных интерфейсов в языке C#, расположенный в пространстве имён System.Collections. Он представляет собой контракт, который гарантирует, что объект поддерживает последовательный перебор элементов, то есть является перечисляемым (enumerable). Его основное предназначение — обеспечить единообразный механизм итерации по коллекциям, массивам и другим наборам данных, не раскрывая их внутреннюю структуру.

Ключевые аспекты IEnumerable

Сигнатура интерфейса:

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

Интерфейс содержит единственный метод GetEnumerator(), который возвращает объект типа IEnumerator. Именно этот объект (перечислитель) реализует логику перемещения по элементам коллекции.

Основные принципы работы:

  1. Ленивое выполнение (Lazy Evaluation): Перебор элементов обычно происходит "по требованию". Элементы не загружаются в память заранее, а извлекаются последовательно в процессе итерации.
  2. Сокрытие реализации: Потребителю не важно, как именно хранятся данные (массив, список, дерево, поток данных). Ему достаточно возможности пройти по элементам.
  3. Совместимость с foreach: Любой тип, реализующий IEnumerable, может использоваться в цикле foreach, что делает код чище и безопаснее (не требует ручного управления индексом).

Пример базового использования

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        // Массив реализует IEnumerable
        int[] numbers = { 10, 20, 30, 40, 50 };
        
        // Цикл foreach работает благодаря IEnumerable
        foreach (int num in numbers)
        {
            Console.WriteLine(num);
        }
        
        // Вручную через GetEnumerator()
        IEnumerator enumerator = numbers.GetEnumerator();
        while (enumerator.MoveNext())
        {
            Console.WriteLine(enumerator.Current);
        }
    }
}

Обобщённая версия IEnumerable<T>

В современном C# чаще используется обобщённая версия IEnumerable<T> (из System.Collections.Generic), которая обеспечивает типобезопасность и лучше интегрируется с LINQ.

public interface IEnumerable<out T> : IEnumerable
{
    new IEnumerator<T> GetEnumerator();
}

Преимущества IEnumerable<T>:

  • Типобезопасность: Не требуется приведение типов.
  • Поддержка ковариантности: Благодаря модификатору out, можно присваивать коллекции производных типов коллекциям базовых типов.
  • Интеграция с LINQ: Все стандартные операции LINQ (Where, Select, OrderBy) работают именно с IEnumerable<T>.
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<string> cities = new List<string> { "Москва", "Санкт-Петербург", "Казань" };
        
        // LINQ-запрос к IEnumerable<T>
        var longCities = cities.Where(c => c.Length > 6);
        
        foreach (var city in longCities)
        {
            Console.WriteLine(city); // "Санкт-Петербург"
        }
    }
}

Когда следует использовать IEnumerable?

  • Для чтения данных только вперёд: Если нужен последовательный доступ без модификации.
  • При работе с большими данными: Благодаря ленивому выполнению, можно обрабатывать потоки данных без полной загрузки в память.
  • В публичных API: Возвращая IEnumerable, вы скрываете внутреннюю структуру данных и даёте клиенту максимальную гибкость.
  • Для поддержки LINQ: Любая кастомная коллекция, реализующая IEnumerable<T>, автоматически становится совместимой с LINQ.

Ограничения

  • Только для чтения: Не позволяет напрямую модифицировать коллекцию.
  • Однопроходность: Обычно перечислитель проходит коллекцию только один раз (хотя можно получить новый перечислитель через GetEnumerator()).
  • Не гарантирует многопоточность: Стандартные реализации не являются потокобезопасными.

Реализация собственного IEnumerable

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

class CustomCollection<T> : IEnumerable<T>
{
    private T[] _items;
    
    public CustomCollection(T[] items)
    {
        _items = items;
    }
    
    public IEnumerator<T> GetEnumerator()
    {
        for (int i = 0; i < _items.Length; i++)
        {
            yield return _items[i]; // Использование yield для упрощения
        }
    }
    
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator(); // Явная реализация необобщённого метода
    }
}

// Использование
var collection = new CustomCollection<int>(new[] { 1, 2, 3 });
foreach (var item in collection)
{
    Console.WriteLine(item);
}

Заключение

IEnumerable и IEnumerable<T> являются краеугольными камнями системы коллекций C#. Они обеспечивают унифицированный способ итерации, поддерживают принцип инкапсуляции, позволяют работать с бесконечными последовательностями и служат фундаментом для мощной технологии LINQ. Понимание этого интерфейса критически важно для эффективной работы с коллекциями и написания идиоматического кода на C#.

Что такое интерфейс IEnumerable? | PrepBro