Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
IEnumerable: Назначение и применение
IEnumerable - это фундаментальный интерфейс в .NET/C#, который определяет возможность итерации по коллекции элементов. Это одно из самых важных понятий в экосистеме .NET.
Что такое IEnumerable
// Базовое определение интерфейса
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerable<T>
{
IEnumerator<T> GetEnumerator();
}
Это интерфейс, который:
- Позволяет перебирать элементы коллекции
- Работает с циклом
foreach - Является основой для LINQ
Зачем он нужен
1. Единый способ итерации
// Без IEnumerable - каждая коллекция работает по-своему
int[] numbers = { 1, 2, 3 };
List<string> names = new() { "Alice", "Bob" };
Dictionary<int, string> dict = new() { { 1, "One" } };
// Все они работают по-разному без общего интерфейса
// Нужно знать API каждой коллекции
// С IEnumerable - единый интерфейс для всех
public void PrintItems<T>(IEnumerable<T> items)
{
foreach (var item in items) // работает для всех!
{
Console.WriteLine(item);
}
}
PrintItems(numbers); // Array
PrintItems(names); // List
PrintItems(dict.Values); // Dictionary values
2. LINQ зависит от IEnumerable
var numbers = new[] { 1, 2, 3, 4, 5 };
// LINQ работает благодаря IEnumerable
var result = numbers
.Where(x => x > 2) // IEnumerable<int>
.Select(x => x * 2) // IEnumerable<int>
.OrderByDescending(x => x) // IEnumerable<int>
.ToList(); // Список
// Все методы LINQ (Where, Select, GroupBy, Join и т.д.)
// работают с IEnumerable
Практический пример
// Собственная реализация IEnumerable
public class StudentCollection : IEnumerable<Student>
{
private List<Student> students = new();
public void Add(Student student) => students.Add(student);
// Реализуем требуемый интерфейс
public IEnumerator<Student> GetEnumerator()
{
// Можем кастомизировать порядок итерации
return students.OrderBy(s => s.Name).GetEnumerator();
}
// Требуется и неgeneric версия
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// Использование
var students = new StudentCollection();
students.Add(new Student { Name = "Bob", Age = 20 });
students.Add(new Student { Name = "Alice", Age = 19 });
// foreach работает благодаря IEnumerable
foreach (var student in students) // Итерируем в порядке сортировки
{
Console.WriteLine(student.Name);
}
IEnumerable vs IEnumerator
// IEnumerable - представляет КОЛЛЕКЦИЮ
public interface IEnumerable<T>
{
IEnumerator<T> GetEnumerator(); // Возвращает итератор
}
// IEnumerator - представляет сам ПРОЦЕСС итерации
public interface IEnumerator<T> : IDisposable
{
T Current { get; } // Текущий элемент
bool MoveNext(); // Переместиться на следующий
void Reset(); // Вернуться в начало
}
// Пример работы
var items = new int[] { 10, 20, 30 }; // IEnumerable<int>
var enumerator = items.GetEnumerator(); // Получаем IEnumerator
while (enumerator.MoveNext()) // Перемещаемся на следующий
{
Console.WriteLine(enumerator.Current); // Получаем текущий
}
// Это эквивалентно:
foreach (var item in items)
{
Console.WriteLine(item);
}
IEnumerable vs ICollection vs IList
// IEnumerable - можно только перебирать
public interface IEnumerable<T>
{
IEnumerator<T> GetEnumerator();
}
// ICollection добавляет методы для работы с коллекцией
public interface ICollection<T> : IEnumerable<T>
{
int Count { get; } // Количество элементов
bool IsReadOnly { get; } // Только для чтения?
void Add(T item); // Добавить
void Clear(); // Очистить
bool Contains(T item); // Содержит?
void CopyTo(T[] array, int arrayIndex); // Копировать
bool Remove(T item); // Удалить
}
// IList - полный контроль над коллекцией
public interface IList<T> : ICollection<T>
{
T this[int index] { get; set; } // Индексер
int IndexOf(T item); // Индекс элемента
void Insert(int index, T item); // Вставить по индексу
void RemoveAt(int index); // Удалить по индексу
}
// Использование
public void ProcessData(IEnumerable<int> data)
{
// Можно только итерировать
foreach (var item in data) { }
// data.Count(); // Ошибка! Нет Count
// data.Add(5); // Ошибка! Нет Add
}
public void ProcessCollection(ICollection<int> data)
{
// Можем итерировать И узнать размер
Console.WriteLine(data.Count);
foreach (var item in data) { }
// data[0]; // Ошибка! Нет индексера
}
public void ProcessList(IList<int> data)
{
// Полный контроль
Console.WriteLine(data.Count);
var first = data[0]; // Индексация
data.Add(100); // Добавление
data.RemoveAt(0); // Удаление по индексу
foreach (var item in data) { } // Итерация
}
IEnumerable и отложенное выполнение (Lazy Evaluation)
// Одно из главных преимуществ IEnumerable
public IEnumerable<int> GetNumbers()
{
for (int i = 1; i <= 1000000; i++)
{
yield return i; // Возвращает элементы по одному
}
}
// Данные не загружаются в памяти!
var result = GetNumbers()
.Where(x => x % 2 == 0) // Применяется постепенно
.Take(10); // Берём только 10
// Реальное вычисление происходит только при итерации
foreach (var num in result)
{
Console.WriteLine(num); // Вычисляется налету
}
// С List<T> пришлось бы загрузить все 1000000 элементов в память!
var badApproach = GetNumbers().ToList(); // Вся память занята
Кастомный IEnumerable с yield
public class FibonacciSequence : IEnumerable<int>
{
private int count;
public FibonacciSequence(int count) => this.count = count;
public IEnumerator<int> GetEnumerator()
{
int prev = 0, curr = 1;
for (int i = 0; i < count; i++)
{
yield return curr;
int next = prev + curr;
prev = curr;
curr = next;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
// Использование
var fib = new FibonacciSequence(10);
foreach (var num in fib)
{
Console.WriteLine(num); // 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
}
// Или с LINQ
var firstFive = new FibonacciSequence(100)
.Take(5)
.ToList(); // { 1, 1, 2, 3, 5 }
Где используется в фронтенде (Full-stack)
Если ты работаешь с ASP.NET Core бэкендом:
// API возвращает данные через IEnumerable
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
[HttpGet]
public IEnumerable<UserDto> GetAll()
{
return _userService.GetAllUsers(); // IEnumerable
}
[HttpGet("active")]
public IEnumerable<UserDto> GetActive()
{
// LINQ работает с IEnumerable
return _userService.GetAllUsers()
.Where(u => u.IsActive)
.OrderBy(u => u.Name);
}
}
Заключение
IEnumerable - это:
- Стандартный способ итерации по коллекциям в .NET
- Основа LINQ - самой мощной функции C#
- Поддерживает отложенное выполнение - экономит память и производительность
- Упрощает код - один интерфейс для разных коллекций
В Full-stack разработке это критичное знание, особенно при работе с ASP.NET Core бэкендом.