Все, что вы можете перебирать в .NET, реализует IEnumerable

Вступление

Это две очень старые концепции программирования, реализованные на большинстве языков в настоящее время, и это руководство поможет вам лучше понять общие интерфейсы IEnumberable и IEnumberator.

Фон

Что такое шаблон проектирования итератора

Определение Gof:

Предоставляет способ обхода элементов агрегированного объекта без раскрытия базового представления.

Агрегатный объект может быть:

  • структура данных
  • Коллекция
  • список
  • последовательность однотипных вещей

Некоторые из требований при повторении элементов в реальном мире могут включать:

  1. Перемещайтесь по-разному, например, вперед, назад, по предварительному заказу или по порядку и т. Д.
  2. Следите за указанными выше способами обхода одной и той же коллекции сразу
  3. Просматривайте разные типы агрегатных объектов одним и тем же способом.

Для списка наиболее простым и известным решением является цикл for. Мы можем использовать локальную целочисленную переменную, чтобы отслеживать текущую позицию элемента в списке.

for (int i = 0; i < 5; i++) {
   object current = myList[i]
}

Одним из недостатков внешнего вида for является то, что он работает только с коллекцией, которую можно проиндексировать, например с массивом или списком. Есть много других структур данных, не имеющих индексов, например binary tree.

Что если даже с индексированным списком или массивом, если они бесконечны или размер неизвестен?

Почему коллекция не может управлять своим обходом

Вместо использования индекса для просмотра коллекции, которая ограничена типом структуры данных. Вероятно, мы можем использовать интервальный частный указатель, который хранится внутри самого класса, чтобы отслеживать текущий элемент. Этот класс также может иметь некоторые дополнительные методы для обхода.

Следует отметить, что это решение допускает только один обход за один раз и не удовлетворяет ни одному из трех требований выше. Нам по-прежнему нужно вручную добавлять в класс дополнительные методы для каждого алгоритма обхода.

Реализация шаблона проектирования .NET Iterator

Мы предполагаем, что класс включает в себя набор элементов и других свойств или методов. Вместо использования самой коллекции мы определяем другой объект, который берет на себя ответственность за обход. Этот специализированный объект только отвечает за прохождение коллекции определенным образом.

Например, этот специализированный объект может содержать указатель для отслеживания текущего элемента и, возможно, некоторые другие методы для реализации логики обхода.

Начиная с .NET framework v1, шаблон итератора уже поддерживается за счет использования двух типов интерфейса пространства имен System.Collections.

  • IEnumerator: точный специализированный объект, отвечающий за обход
  • IEnumberable: структура данных, которую можно просматривать.

.NET использует enumerate, а не iterate, на самом деле они одинаковы. Так что вы можете подумать о enumerate design pattern, если хотите. Еще хочу отметить, что перечислитель здесь не имеет ничего общего с типом ENUM (перечислимый тип).

Как работает IEnumerator

Интерфейс IEnumerator на самом деле является сутью шаблона, который определяет простейший из возможных способов обхода структуры данных. Объект перечислителя содержит элемент Current в процессе обхода. И когда вы укажете ему перейти к следующему элементу с помощью флага MoveNext bool, Current будет указывать на следующий элемент. Когда у нас закончатся элементы для продолжения (до последнего в коллекции), MoveNext станет false.

Мы можем заметить, что интерфейс IEnumerator не делает никаких предположений относительно структуры данных, внутренних подробных реализаций или размера коллекций. Возможно, это самое чистое понятие «последовательности», которое я могу придумать.

Если коллекция или последовательность включает в себя перечислитель, теоретически мы можем перебирать любую структуру агрегированных данных. Здесь вступает в игру IEnumberable интерфейс.

Что такое IEnumerable

Интерфейс IEnumerable определяет стандартизованный способ получения объекта перечислителя. Чтобы получить экземпляр перечислителя, весь класс коллекции или последовательности должен реализовывать интерфейс IEnumerable и обеспечивать собственную реализацию того, как должен выглядеть перечислитель.

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

В .NET все типы коллекций реализовали интерфейс IEnumerable и даже класс String.

Как их использовать

Поддержка языка C #

Шаблон проектирования перечислителя довольно прост, он просто получает перечислитель из класса и вызывает MoveNext в цикле. Объект перечислителя берет на себя полную ответственность за обход. Поскольку этот шаблон использования настолько распространен, что язык C # формализует его с помощью ключевого слова foreach, которое является чисто синтаксическим сахаром.

Следующий код идентичен предыдущему примеру.

Компилятор C # просто скомпилирует синтаксис foreach в тот же код (промежуточный язык), что и в предыдущем примере

Заключение

В общем, понимание того, откуда взялся шаблон проектирования перечислителя, очень полезно. Я надеюсь, что это было информативным, и вы нашли то, что искали.