Различие между итератором и перечислителем

Вопрос интервью для задания .NET 3.5: "В чем разница между итератором и перечислителем"?

Это основное отличие сделать, что с LINQ и т.д.

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

ИМО итератор "итерации" над сборником, и перечислитель предоставляет функциональность для итерации, но это нужно назвать.

Кроме того, говорят, что использование ключевого слова yield сохраняет состояние. Что это за состояние? Есть ли пример этого преимущества?

Ответ 1

Итерация означает повторение некоторых шагов, в то время как перечисление означает перенос всех значений в наборе значений. Поэтому перечисление обычно требует некоторой формы итерации.

Таким образом, перечисление является частным случаем итерации, где шаг получает значение из коллекции.

Обратите внимание, что "обычно" - перечисление также может выполняться рекурсивно, но рекурсия и итерация настолько тесно связаны, что меня не волнует эта небольшая разница.

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


Я полагаю, что Рид Копси понял. В С# есть два основных способа перечислить что-то.

  • Внедрить Enumerable и реализовать класс IEnumerator
  • Внедрить итератор с оператором yield

Первый способ сложнее реализовать и использует объекты для перечисления. Второй способ проще реализовать и использовать продолжения.

Ответ 2

В С# 2+ - это способ для компилятора автоматически генерировать IEnumerable и/или IEnumerable <T> интерфейсы для вас.

Без итераторов вам нужно будет создать класс, реализующий IEnumerator, включая Current, MoveNext и Reset. Для этого требуется достаточная работа. Обычно вы создадите частный класс, который реализует IEnumerator <T> для вашего типа, тогда вашClass.GetEnumerator() создаст этот частный класс и вернет его.

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

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

Когда вы используете foreach, они будут вести себя одинаково (если вы правильно напишите свой собственный IEnumerator). Итераторы просто делают жизнь намного проще.

Ответ 3

Что С# вызывает итератор чаще (вне мира С#), называемый generator или функции генератора (например, в Python). Функция-генератор - это специализированный случай сопрограмма. Итератор С# (генератор) является специальной формой перечислителя (тип данных, реализующий интерфейс IEnumerable).

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

Для сравнения рассмотрим, что в С++ итератор является значением, которое используется в основном для доступа к последовательным элементам в коллекции. Он может быть расширен, привязан для получения значения и проверен, чтобы узнать, достигнут ли конец коллекции.

Ответ 4

Чтобы понять итераторы, нам сначала нужно понять перечисления.

Перечислители - это специализированные объекты, которые предоставляют возможность перемещения по упорядоченному списку предметов по одному (тот же самый тип иногда называют "курсором" ). В .NET Framework предусмотрены два важных интерфейса, относящихся к счетчикам: IEnumerator и IEnumerable. Объекты, которые реализуют IEnumerator, сами являются перечисляющими; они поддерживают следующих членов:

  • свойство Current, которое указывает на позицию в списке

  • метод MoveNext, который перемещает текущий элемент по списку

  • метод Reset, который перемещает текущий элемент в исходное положение (которое находится перед первым элементом).

С другой стороны, Итераторы реализуют счетчик..NET 2.0 представил итератор, который является компилятором-перемножаемым энтузиастом. Когда перечисляемый объект получает GetEnumertor, прямо или косвенно, компилятор генерирует и возвращает апробативный итераторный объект. Возможно, итератор может быть объединенным перечислимым и энтузиастским объектом.

Существенным компонентом итераторного блока является способность к выходу. Существует большая разница между итераторами и энтузиастами: Итераторы не реализуют метод Reset. С помощью метода Reset на итераторе исключается исключение.

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

Ответ 5

"В то время как оператор foreach является потребителем перечислителя, итератор является производителем перечислителя."

Выше описано, как "С# 5.0 In A NutShell" объясняет это и помогло мне.

Другими словами, оператор foreach использует MoveNext() и текущее свойство IEnumerator для итерации по последовательности, в то время как итератор используется для создания реализации IEnumerator, который будет использоваться оператором foreach. В С#, когда вы пишете метод итератора, содержащий оператор yield, компилятор будет генерировать для вас частный перечислитель. И когда вы перебираете элементы в последовательности, он будет вызывать свойство MoveNext() и Current частного счетчика. Эти методы/свойства реализуются вашим кодом в методе итератора, который будет вызываться повторно, чтобы получить значения, пока не осталось значений.

Это мое понимание того, как С# определяют счетчики и итераторы.

Ответ 6

Так как примеров не было, вот то, что мне было полезно.

Перечислитель - это объект, который вы получаете при вызове .GetEnumerator() для класса или типа, который реализует интерфейс IEnumerator. Когда этот интерфейс реализован, вы создали весь код, необходимый для компилятора, чтобы вы могли использовать foreach для "итерации" по вашей коллекции.

Не заставляйте это слово "итерацию" путать с итератором. И как Enumerator, так и итератор позволяют вам "итерации". Перечисление и итерация - это в основном один и тот же процесс, но выполняются по-разному. Перечисление означает, что вы имплантировали интерфейс IEnumerator. Итерация означает, что вы создали конструкцию итератора в своем классе (показано ниже), и вы вызываете foreach в свой класс, и в это время компилятор автоматически создает для вас функцию перечисления.

Также обратите внимание, что вам не нужно приседать с вашим перечислителем. Вы можете вызывать MyClass.GetEnumerator() весь день и ничего не делать с ним (пример:

IEnumerator myEnumeratorThatIWillDoNothingWith = MyClass.GetEnumerator()).

Обратите внимание, что ваш конструктор итератора в вашем классе реально используется, когда вы его используете, т.е. вы вызывали foreach в своем классе.

Вот пример итератора из msdn:

public class DaysOfTheWeek : System.Collections.IEnumerable
{

     string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

     //This is the iterator!!!
     public System.Collections.IEnumerator GetEnumerator()
     {
         for (int i = 0; i < days.Length; i++)
         {
             yield return days[i];
         }
     }

}

class TestDaysOfTheWeek
{
    static void Main()
    {
        // Create an instance of the collection class
        DaysOfTheWeek week = new DaysOfTheWeek();

        // Iterate with foreach - this is using the iterator!!! When the compiler
        //detects your iterator, it will automatically generate the Current, 
        //MoveNext and Dispose methods of the IEnumerator or IEnumerator<T> interface
        foreach (string day in week)
        {
            System.Console.Write(day + " ");
        }
    }
}
// Output: Sun Mon Tue Wed Thr Fri Sat

Ответ 7

"Итераторы - это новая функция в С# 2.0. Итератор - это метод, get accessor или operator, который позволяет вам поддерживать итерацию foreach в классе или структуре без необходимости реализации всего интерфейса IEnumerable. Вместо этого вы предоставляете только iterator, который просто перемещает структуры данных в вашем классе. Когда компилятор обнаруживает ваш итератор, он автоматически генерирует методы Current, MoveNext и Dispose интерфейса IEnumerable или IEnumerable." - msdn

Ответ 8

Перечисление относится к объектам, а итерация - только значениям. Перечисление используется, когда мы используем векторную хэш-таблицу и т.д., В то время как итерация используется во время цикла для цикла и т.д. Я никогда не использовал ключевое слово yield, поэтому я не мог сказать вам.