Вопрос

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

Это основное различие, которое необходимо провести, как с LINQ и т.д.

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

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

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

Это было полезно?

Решение

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

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

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

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


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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Однако не путайте это слово "iterate" с iterator .Как перечислитель, так и итератор позволяют вам "выполнять итерации".Перечисление и итерация - это в основном один и тот же процесс, но реализованы они по-разному.Перечисление означает, что вы внедрили интерфейс IEnumerator.Выполнение итерации означает, что вы создали конструкцию iterator в своем классе (продемонстрировано ниже), и вы вызываете 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 или оператор, который позволяет вам поддерживать каждую итерацию в классе или структуре без необходимости реализации всего интерфейса IEnumerable.Вместо этого вы предоставляете просто итератор, который просто просматривает структуры данных в вашем классе.Когда компилятор обнаружит ваш итератор, он автоматически сгенерирует методы Current, MoveNext и Dispose интерфейса IEnumerable или IEnumerable." - msdn

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top