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


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

Это основное различие, которое нужно сделать, что с LINQ и т. д.

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

IMO итератор "повторяет" над a коллекция и перечислитель предоставляют функциональные возможности для итерации, но это должно быть вызвано.

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

8 68

8 ответов:

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

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

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

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


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

  1. реализовать Enumerable и класс, реализующий IEnumerator
  2. реализовать итератор с yield сообщении

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

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

без итераторов вам нужно будет создать класс, реализующий IEnumerator, включая текущий, MoveNext и сброс. Это требует изрядного объема работы. Обычно вы создаете частный класс, который имплемтирует IEnumerator для вашего типа, а затем yourClass.Метод getenumerator() бы построить, что частная класс, и вернуть его.

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

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

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

то, что C# называет итератор чаще всего (за пределами мира C#) называется a генератор или функции генератора (например, в Python). Функция генератора является специализированным случаем coroutine. Итератор (генератор) C# является специальной формой перечислитель (тип данных реализации IEnumerable интерфейс).

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

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

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

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

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

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

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

с другой стороны, итераторы реализуют шаблон перечислителя. .NET 2.0 представил итератор, который является а компилятор-проявленный перечислитель. Когда перечисляемый объект вызывает GetEnumerator, прямо или косвенно, компилятор создает и возвращает соответствующий объект итератора. При необходимости, итератор может быть а в сочетании перечисляемый объект и перечислителя.

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

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

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

выше, как" C# 5.0 в двух словах " объясняет это, и было полезно для меня.

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

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

так как никаких примеров не было дано, вот один, который был полезен для меня.

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

не поймите, что слово "итерация" путают с итератором, хотя. Как перечислитель, так и итератор позвольте вам "повторить". Перечисление и итерация-это в основном один и тот же процесс, но реализуются по-разному. Перечисление означает, что вы имплантировали интерфейс 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

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

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