Может кто-нибудь объяснить мне IEnumerable и IEnumerator?
например, когда использовать его поверх foreach? В чем разница между IEnumerable и IEnumerator? Почему мы должны использовать это?
c#
ienumerable
ienumerator
prodev42
источник
источник
Ответы:
Вы не используете
IEnumerable
«более»foreach
. РеализацияIEnumerable
делаетforeach
возможным использование .Когда вы пишете код вроде:
это функционально эквивалентно написанию:
Под «функционально эквивалентным» я подразумеваю, что это фактически то, во что компилятор превращает код. Вы не можете использовать
foreach
наbaz
в данном примере исключения случаев , когдаbaz
инвентарьIEnumerable
.IEnumerable
означает, чтоbaz
реализует методIEnumerator
Объект, этот метод возвращает должны реализовать методыи
Первый метод переходит к следующему объекту в
IEnumerable
объекте, который создал перечислитель, возвращая,false
если это сделано, а второй возвращает текущий объект.Все, что вы можете перебирать в .Net
IEnumerable
. Если вы создаете свой собственный класс, и он еще не наследуется от реализующего его классаIEnumerable
, вы можете сделать его пригодным для использования вforeach
выражениях, реализовав егоIEnumerable
(и создав класс перечислителя,GetEnumerator
который вернет его новый метод).источник
bool MoveNext()
метод иCurrent
свойство любого типа. Этот подход "утиной типизации" был реализован в C # 1.0 как способ избежать упаковки при перечислении коллекций типа значения.iterator
?Интерфейсы IEnumerable и IEnumerator
Чтобы начать изучение процесса реализации существующих интерфейсов .NET, давайте сначала посмотрим на роль IEnumerable и IEnumerator. Напомним, что C # поддерживает ключевое слово с именем foreach, которое позволяет перебирать содержимое любого типа массива:
Хотя может показаться, что эту конструкцию могут использовать только типы массивов, правда в том, что любой тип, поддерживающий метод с именем GetEnumerator (), может быть оценен конструкцией foreach. Для иллюстрации следуйте за мной!
Предположим, у нас есть класс Garage:
В идеале было бы удобно перебирать подэлементы объекта Garage, используя конструкцию foreach, как массив значений данных:
К сожалению, компилятор сообщает вам, что класс Garage не реализует метод с именем GetEnumerator (). Этот метод формализован интерфейсом IEnumerable, который находится в пространстве имен System.Collections. Классы или структуры, поддерживающие это поведение, объявляют, что они могут предоставить вызывающим элементам вложенные подэлементы (в этом примере - само ключевое слово foreach). Вот определение этого стандартного интерфейса .NET:
Как видите, метод GetEnumerator () возвращает ссылку на еще один интерфейс с именем System.Collections.IEnumerator. Этот интерфейс обеспечивает инфраструктуру, позволяющую вызывающей стороне проходить внутренние объекты, содержащиеся в IEnumerable-совместимом контейнере:
Если вы хотите обновить тип Garage для поддержки этих интерфейсов, вы можете проделать долгий путь и реализовать каждый метод вручную. Хотя вы, безусловно, можете предоставить настроенные версии GetEnumerator (), MoveNext (), Current и Reset (), существует более простой способ. Поскольку тип System.Array (как и многие другие классы коллекций) уже реализует IEnumerable и IEnumerator, вы можете просто делегировать запрос System.Array следующим образом:
После того, как вы обновили тип Garage, вы можете безопасно использовать его в конструкции foreach C #. Кроме того, учитывая, что метод GetEnumerator () был определен публично, пользователь объекта может также взаимодействовать с типом IEnumerator:
Однако, если вы предпочитаете скрыть функциональность IEnumerable от уровня объекта, просто используйте явную реализацию интерфейса:
При этом пользователь случайного объекта не найдет метод GetEnumerator () в Garage, а конструкция foreach при необходимости получит интерфейс в фоновом режиме.
Адаптировано из Pro C # 5.0 и .NET 4.5 Framework
источник
Garage
который получаетcarArray
? Таким образом, вам не нужно реализовыватьGetEnumerator
себя, так какArray
уже делает это. Напримерforeach(Car c in carLot.getCars()) { ... }
Реализация IEnumerable означает, что ваш класс возвращает объект IEnumerator:
Реализация IEnumerator означает, что ваш класс возвращает методы и свойства для итерации:
В любом случае это разница.
источник
Объяснение через Analogy + Code Walkthrough
Сначала объяснение без кода, потом я добавлю его позже.
Допустим, вы управляете авиакомпанией. И в каждом самолете вы хотите узнать информацию о пассажирах, летящих в самолете. В основном вы хотите, чтобы иметь возможность "пересечь" самолет. Другими словами, вы хотите иметь возможность начать с переднего сиденья, а затем направиться к задней части самолета, задавая пассажирам некоторую информацию: кто они, откуда они и т. Д. Самолет может делать только это. , если это:
Почему эти требования? Потому что это то, что требует интерфейс.
Если это информационная перегрузка, вам нужно знать только то, что вы хотите задать каждому пассажиру в самолете несколько вопросов, начиная с первого и заканчивая последним.
Что значит счетное?
Если авиакомпания является «счетной», это означает, что в самолете ДОЛЖЕН присутствовать стюардесса, единственной задачей которой является подсчет - и эта стюардесса ДОЛЖНА вести подсчет весьма специфическим образом:
Процедуры подсчета
Капитан авиакомпании хочет получить отчет о каждом пассажире, когда и когда он расследуется или подсчитывается. Таким образом, после разговора с человеком на первом месте, стюардесса / счетчик затем сообщает капитану, и когда отчет предоставляется, счетчик запоминает его / ее точное положение в проходе и продолжает считать прямо там, где он / она ушел. выкл.
Таким образом, капитан всегда может получить информацию о текущем человеке, находящемся под следствием. Таким образом, если он узнает, что этот человек любит Манчестер Сити, то он может предоставить этому пассажиру льготный режим и т. Д.
Давайте свяжем это с IEnumerables
Enumerable - это просто набор пассажиров в самолете. Закон о гражданской авиации - это в основном правила, которым должны следовать все IEnumerables. Каждый раз, когда стюардесса отправляется к капитану с информацией о пассажирах, мы в основном «уступаем» пассажира капитану. Капитан может в основном делать с пассажиром все, что захочет, за исключением перестановки пассажиров в самолете. В этом случае им предоставляется преференциальный режим, если они следуют за Манчестер Сити (тьфу!)
Резюме
Другими словами, что-то исчисляется, если у него есть счетчик . И счетчик должен (в основном): (i) помнить свое место ( состояние ), (ii) быть в состоянии двигаться дальше , (iii) и знать о текущем человеке, с которым он имеет дело.
Enumerable - это просто причудливое слово для «счетного». Другими словами, перечислимое позволяет вам «перечислять» (т.е. считать).
источник
IEnumerable реализует GetEnumerator. При вызове этот метод возвращает IEnumerator, который реализует MoveNext, Reset и Current.
Таким образом, когда ваш класс реализует IEnumerable, вы говорите, что можете вызвать метод (GetEnumerator) и получить новый возвращенный объект (IEnumerator), который вы можете использовать в цикле, таком как foreach.
источник
Реализация IEnumerable позволяет вам получить IEnumerator для списка.
IEnumerator допускает последовательный доступ к элементам списка в стиле foreach, используя ключевое слово yield.
До реализации foreach (например, в Java 1.4) способ итерации списка состоял в том, чтобы получить перечислитель из списка, а затем запросить у него «следующий» элемент в списке, пока значение возвращается как следующее Элемент не является нулевым. Foreach просто делает это неявно в качестве языковой функции, точно так же, как lock () реализует класс Monitor за кулисами.
Я ожидаю, что foreach работает со списками, потому что они реализуют IEnumerable.
источник
Думайте о перечисляемых объектах как о списках, стеках, деревьях.
источник
IEnumerable и IEnumerator (и их общие аналоги IEnumerable <T> и IEnumerator <T>) являются базовыми интерфейсами реализаций итераторов в коллекциях .Net Framework Class Libray .
IEnumerable - это самый распространенный интерфейс, который вы видели бы в большинстве кода. Он включает цикл foreach, генераторы (думаю, что доходность ) и благодаря своему крошечному интерфейсу используется для создания узких абстракций. IEnumerable зависит от IEnumerator .
IEnumerator , с другой стороны, предоставляет интерфейс итерации немного более низкого уровня. Он называется явным итератором, который дает программисту больший контроль над циклом итерации.
IEnumerable
IEnumerable - это стандартный интерфейс, который позволяет перебирать коллекции, которые его поддерживают (фактически, все типы коллекций, о которых я могу думать сегодня, реализуют IEnumerable ). Поддержка компилятора позволяет такие функции языка, как
foreach
. В общих чертах, это позволяет эту неявную реализацию итератора .петля foreach
Я думаю, что
foreach
цикл является одной из основных причин использования интерфейсов IEnumerable .foreach
имеет очень сжатый синтаксис и очень прост для понимания по сравнению с классическим стилем C для циклов, где вам нужно проверять различные переменные, чтобы увидеть, что он делает.дать ключевое слово
Вероятно, менее известная особенность в том , что IEnumerable также позволяет генераторы в C # с использованием
yield return
иyield break
отчетностью.Абстракции
Другим распространенным сценарием на практике является использование IEnumerable для предоставления минималистических абстракций. Поскольку это крошечный и доступный только для чтения интерфейс, рекомендуется представлять свои коллекции как IEnumerable (а не List, например). Таким образом, вы можете свободно изменять свою реализацию, не нарушая код вашего клиента (например, измените List на LinkedList ).
Попался
Следует помнить о том, что при реализации потоковой передачи (например, извлечение данных строка за строкой из базы данных вместо загрузки сначала всех результатов в память) вы не можете перебирать коллекцию более одного раза. Это отличается от коллекций в памяти, таких как List , где вы можете выполнять многократные итерации без проблем. ReSharper, например, имеет проверку кода для возможного множественного перечисления IEnumerable .
IEnumerator
IEnumerator, с другой стороны, является скрытым интерфейсом, который заставляет IEnumerble-foreach-magic работать. Строго говоря, он допускает явные итераторы.
По моему опыту, IEnumerator редко используется в распространенных сценариях из-за его более многословного синтаксиса и немного сбивающей с толку семантики (по крайней мере для меня; например, MoveNext () также возвращает значение, которое имя не предлагает вообще).
Вариант использования для IEnumerator
Я использовал только IEnumerator, в частности (немного более низкого уровня) библиотеки и платформы, где я предоставлял интерфейсы IEnumerable . Одним из примеров является библиотека обработки потока данных, которая предоставляла серии объектов в
foreach
цикле, даже если за кадром данные собирались с использованием различных файловых потоков и сериализаций.Код клиента
Библиотека
источник
Реализация по
IEnumerable
существу означает, что объект может быть повторен. Это не обязательно означает, что это массив, поскольку есть определенные списки, которые нельзя индексировать, но вы можете перечислить их.IEnumerator
фактический объект, используемый для выполнения итераций. Он контролирует перемещение от одного объекта к другому в списке.Большую часть времени
IEnumerable
&IEnumerator
прозрачно используются как частьforeach
цикла.источник
Различия между IEnumerable и IEnumerator:
Всякий раз, когда мы передаем коллекцию IEnumerable другой функции, она не знает текущей позиции элемента / объекта (не знает, какой элемент ее выполняет)
IEnumerable имеет один метод GetEnumerator ()
IEnumerator имеет одно свойство с именем Current и два метода, Reset () и MoveNext () (которые полезны для определения текущей позиции элемента в списке).
источник
IEnumerable - это блок, содержащий Ienumerator. IEnumerable является базовым интерфейсом для всех коллекций. Цикл foreach может работать, если коллекция реализует IEnumerable. В приведенном ниже коде объясняется, как создать собственный перечислитель. Давайте сначала определим наш класс, из которого мы собираемся сделать коллекцию.
Теперь мы определим класс, который будет действовать как коллекция для нашего класса Customer. Обратите внимание, что он реализует интерфейс IEnumerable. Так что нам нужно реализовать метод GetEnumerator. Это вернет наш пользовательский перечислитель.
Теперь мы собираемся создать наш собственный перечислитель следующим образом. Итак, мы должны реализовать метод MoveNext.
Теперь мы можем использовать цикл foreach над нашей коллекцией, как показано ниже;
источник
Понимание шаблона итератора будет полезно для вас. Я рекомендую читать то же самое.
Шаблон итератора
На высоком уровне шаблон итератора может использоваться для обеспечения стандартного способа перебора коллекций любого типа. У нас есть 3 участника в шаблоне итератора, фактическая коллекция (клиент), агрегатор и итератор. Агрегат - это интерфейсный / абстрактный класс, который имеет метод, который возвращает итератор. Iterator - это интерфейсный / абстрактный класс, который имеет методы, позволяющие выполнять итерацию по коллекции.
Чтобы реализовать шаблон, нам сначала нужно реализовать итератор для создания конкретного объекта, который может перебирать соответствующую коллекцию (клиент). Затем коллекция (клиент) реализует агрегатор для возврата экземпляра вышеуказанного итератора.
Вот диаграмма UML
Таким образом, в основном в c # IEnumerable является абстрактным агрегатом, а IEnumerator - абстрактным итератором. IEnumerable имеет единственный метод GetEnumerator, который отвечает за создание экземпляра IEnumerator нужного типа. Коллекции, подобные спискам, реализуют IEnumerable.
Пример. Предположим, что у нас есть метод,
getPermutations(inputString)
который возвращает все перестановки строки, и что метод возвращает экземплярIEnumerable<string>
Чтобы подсчитать количество перестановок, мы можем сделать что-то вроде ниже.
Компилятор c # более или менее преобразует вышеуказанное в
Если у вас есть какие-либо вопросы, пожалуйста, не стесняйтесь спрашивать.
источник
Незначительный вклад.
Как многие из них объясняют, «когда использовать» и «использовать с foreach». Я подумал о том, чтобы добавить здесь другую разницу состояний, как было задано в вопросе о разнице между IEnumerable и IEnumerator.
Я создал приведенный ниже пример кода на основе обсуждений ниже.
IEnumerable, IEnumerator против foreach, когда использовать, в чем разница между IEnumerator и IEnumerable?
Enumerator сохраняет состояние (положение итерации) между вызовами функций, в то время как итерации другой стороны Enumerable не делает.
Вот проверенный пример с комментариями, чтобы понять.
Эксперты, пожалуйста, добавьте / исправьте меня.
источник
Я заметил эти различия:
О. Мы повторяем список по-разному, foreach может использоваться для IEnumerable и цикл while для IEnumerator.
Б. IEnumerator может запомнить текущий индекс, когда мы переходим от одного метода к другому (он начинает работать с текущим индексом), но IEnumerable не может запомнить индекс и сбрасывает индекс до начала. Подробнее в этом видео https://www.youtube.com/watch?v=jd3yUjGc9M0
источник
IEnumerable
иIEnumerator
оба являются интерфейсами в C #.IEnumerable
интерфейс, определяющий единственный метод,GetEnumerator()
который возвращаетIEnumerator
интерфейсЭто работает для доступа только для чтения к коллекции, которая реализуется, которая
IEnumerable
может использоваться сforeach
оператором.IEnumerator
имеет два метода,MoveNext
иReset
. У этого также есть свойство, названноеCurrent
.Ниже показана реализация IEnumerable и IEnumerator.
источник
источник