Может кто-нибудь объяснить мне IEnumerable и IEnumerator? [закрыто]

272

Может кто-нибудь объяснить мне IEnumerable и IEnumerator?

например, когда использовать его поверх foreach? В чем разница между IEnumerable и IEnumerator? Почему мы должны использовать это?

prodev42
источник
55
Это худшее смешение имен с Java и JavaScript
Мэтью Локк
@ MatthewLock вы можете объяснить, что вы имеете в виду?
Дэвид Клемпфнер

Ответы:

275

например, когда использовать его поверх foreach?

Вы не используете IEnumerable«более» foreach. Реализация IEnumerableделает foreach возможным использование .

Когда вы пишете код вроде:

foreach (Foo bar in baz)
{
   ...
}

это функционально эквивалентно написанию:

IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
   bar = (Foo)bat.Current
   ...
}

Под «функционально эквивалентным» я подразумеваю, что это фактически то, во что компилятор превращает код. Вы не можете использовать foreachна bazв данном примере исключения случаев , когда baz инвентарь IEnumerable.

IEnumerableозначает, что bazреализует метод

IEnumerator GetEnumerator()

IEnumeratorОбъект, этот метод возвращает должны реализовать методы

bool MoveNext()

и

Object Current()

Первый метод переходит к следующему объекту в IEnumerableобъекте, который создал перечислитель, возвращая, falseесли это сделано, а второй возвращает текущий объект.

Все, что вы можете перебирать в .Net IEnumerable. Если вы создаете свой собственный класс, и он еще не наследуется от реализующего его класса IEnumerable, вы можете сделать его пригодным для использования в foreachвыражениях, реализовав его IEnumerable(и создав класс перечислителя, GetEnumeratorкоторый вернет его новый метод).

Роберт Россни
источник
15
Я думаю, что когда в исходном плакате говорилось «через foreach», он имел в виду «когда я должен явно вызывать GetEnumerator () / MoveNext () вместо использования цикла foreach». Для чего это стоит.
Mqp
6
Ах, я думаю, что ты прав. Ну, ответ неявный в моем посте: это не имеет значения, так как это делает компилятор в любом случае. Так что делай то, что проще всего, т.е. используй foreach.
Роберт Россни
12
Этот ответ не рассказывает всей истории. Перечислимые объекты не должны реализовывать IEnumerable; им нужен только метод GetEnumerator, который возвращает экземпляр типа, который, в свою очередь, имеет bool MoveNext()метод и Currentсвойство любого типа. Этот подход "утиной типизации" был реализован в C # 1.0 как способ избежать упаковки при перечислении коллекций типа значения.
Фог
3
С объяснением сверху и проработкой Workthrough: реализация IEnumerable of (T) у вас есть отличные источники.
Руэди
4
Это что-то вроде C ++ iterator?
Мэтт G
162

Интерфейсы IEnumerable и IEnumerator

Чтобы начать изучение процесса реализации существующих интерфейсов .NET, давайте сначала посмотрим на роль IEnumerable и IEnumerator. Напомним, что C # поддерживает ключевое слово с именем foreach, которое позволяет перебирать содержимое любого типа массива:

// Iterate over an array of items.
int[] myArrayOfInts = {10, 20, 30, 40};
foreach(int i in myArrayOfInts)
{
   Console.WriteLine(i);
}

Хотя может показаться, что эту конструкцию могут использовать только типы массивов, правда в том, что любой тип, поддерживающий метод с именем GetEnumerator (), может быть оценен конструкцией foreach. Для иллюстрации следуйте за мной!

Предположим, у нас есть класс Garage:

// Garage contains a set of Car objects.
public class Garage
{
   private Car[] carArray = new Car[4];
   // Fill with some Car objects upon startup.
   public Garage()
   {
      carArray[0] = new Car("Rusty", 30);
      carArray[1] = new Car("Clunker", 55);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
}

В идеале было бы удобно перебирать подэлементы объекта Garage, используя конструкцию foreach, как массив значений данных:

// This seems reasonable ...
public class Program
{
   static void Main(string[] args)
   {
      Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
      Garage carLot = new Garage();
      // Hand over each car in the collection?
      foreach (Car c in carLot)
      {
         Console.WriteLine("{0} is going {1} MPH",
         c.PetName, c.CurrentSpeed);
      }
      Console.ReadLine();
   }
}

К сожалению, компилятор сообщает вам, что класс Garage не реализует метод с именем GetEnumerator (). Этот метод формализован интерфейсом IEnumerable, который находится в пространстве имен System.Collections. Классы или структуры, поддерживающие это поведение, объявляют, что они могут предоставить вызывающим элементам вложенные подэлементы (в этом примере - само ключевое слово foreach). Вот определение этого стандартного интерфейса .NET:

// This interface informs the caller
// that the object's subitems can be enumerated.
public interface IEnumerable
{
   IEnumerator GetEnumerator();
}

Как видите, метод GetEnumerator () возвращает ссылку на еще один интерфейс с именем System.Collections.IEnumerator. Этот интерфейс обеспечивает инфраструктуру, позволяющую вызывающей стороне проходить внутренние объекты, содержащиеся в IEnumerable-совместимом контейнере:

// This interface allows the caller to
// obtain a container's subitems.
public interface IEnumerator
{
   bool MoveNext (); // Advance the internal position of the cursor.
   object Current { get;} // Get the current item (read-only property).
   void Reset (); // Reset the cursor before the first member.
}

Если вы хотите обновить тип Garage для поддержки этих интерфейсов, вы можете проделать долгий путь и реализовать каждый метод вручную. Хотя вы, безусловно, можете предоставить настроенные версии GetEnumerator (), MoveNext (), Current и Reset (), существует более простой способ. Поскольку тип System.Array (как и многие другие классы коллекций) уже реализует IEnumerable и IEnumerator, вы можете просто делегировать запрос System.Array следующим образом:

using System.Collections;
...
public class Garage : IEnumerable
{
   // System.Array already implements IEnumerator!
   private Car[] carArray = new Car[4];
   public Garage()
   {
      carArray[0] = new Car("FeeFee", 200);
      carArray[1] = new Car("Clunker", 90);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
   public IEnumerator GetEnumerator()
   {
      // Return the array object's IEnumerator.
      return carArray.GetEnumerator();
   }
}

После того, как вы обновили тип Garage, вы можете безопасно использовать его в конструкции foreach C #. Кроме того, учитывая, что метод GetEnumerator () был определен публично, пользователь объекта может также взаимодействовать с типом IEnumerator:

// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);

Однако, если вы предпочитаете скрыть функциональность IEnumerable от уровня объекта, просто используйте явную реализацию интерфейса:

IEnumerator IEnumerable.GetEnumerator()
{
  // Return the array object's IEnumerator.
  return carArray.GetEnumerator();
}

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

Адаптировано из Pro C # 5.0 и .NET 4.5 Framework

Саид Роохулла Аллем
источник
1
Фантастический ответ, спасибо! У меня есть один вопрос, хотя. В первом примере вы перебираете массив, используя foreach, но затем вы не можете сделать это во втором примере. Это потому, что массив находится в классе или потому что он содержит объекты?
Калеб Палмквист
Спасибо за отличное объяснение. Мой единственный вопрос, почему бы просто не иметь метод, Garageкоторый получает carArray? Таким образом, вам не нужно реализовывать GetEnumeratorсебя, так как Arrayуже делает это. Напримерforeach(Car c in carLot.getCars()) { ... }
Ник Роландо
63

Реализация IEnumerable означает, что ваш класс возвращает объект IEnumerator:

public class People : IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        // return a PeopleEnumerator
    }
}

Реализация IEnumerator означает, что ваш класс возвращает методы и свойства для итерации:

public class PeopleEnumerator : IEnumerator
{
    public void Reset()...

    public bool MoveNext()...

    public object Current...
}

В любом случае это разница.

ядро
источник
1
Хорошо, это объясняет (вместе с другими публикациями), как преобразовать ваш класс в тот, который вы можете использовать «foreach» для перебора его содержимого.
Контанго
54

Объяснение через Analogy + Code Walkthrough

Сначала объяснение без кода, потом я добавлю его позже.

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

  1. исчисляемый и
  2. если у него есть счетчик.

Почему эти требования? Потому что это то, что требует интерфейс.

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

Что значит счетное?

Если авиакомпания является «счетной», это означает, что в самолете ДОЛЖЕН присутствовать стюардесса, единственной задачей которой является подсчет - и эта стюардесса ДОЛЖНА вести подсчет весьма специфическим образом:

  1. Стойка / стюардесса ДОЛЖНА начинаться перед первым пассажиром (перед каждым, где они демонстрируют безопасность, как надеть спасательный жилет и т. Д.).
  2. Он / она (т. Е. Стюардесса) ДОЛЖЕН «двигаться дальше» по проходу к первому месту.
  3. Затем он / она должен записать: (i) кто находится на месте, и (ii) его текущее местоположение в проходе.

Процедуры подсчета

Капитан авиакомпании хочет получить отчет о каждом пассажире, когда и когда он расследуется или подсчитывается. Таким образом, после разговора с человеком на первом месте, стюардесса / счетчик затем сообщает капитану, и когда отчет предоставляется, счетчик запоминает его / ее точное положение в проходе и продолжает считать прямо там, где он / она ушел. выкл.

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

  • Счетчик продолжает идти, пока он не достигнет конца самолета.

Давайте свяжем это с IEnumerables

  • Enumerable - это просто набор пассажиров в самолете. Закон о гражданской авиации - это в основном правила, которым должны следовать все IEnumerables. Каждый раз, когда стюардесса отправляется к капитану с информацией о пассажирах, мы в основном «уступаем» пассажира капитану. Капитан может в основном делать с пассажиром все, что захочет, за исключением перестановки пассажиров в самолете. В этом случае им предоставляется преференциальный режим, если они следуют за Манчестер Сити (тьфу!)

    foreach (Passenger passenger in Plane)
    // the airline hostess is now at the front of the plane
    // and slowly making her way towards the back
    // when she get to a particular passenger she gets some information
    // about the passenger and then immediately heads to the cabin
    // to let the captain decide what to do with it
    { // <---------- Note the curly bracket that is here.
        // we are now cockpit of the plane with the captain.
        // the captain wants to give the passenger free 
        // champaign if they support manchester city
        if (passenger.supports_mancestercity())
        {
            passenger.getFreeChampaign();
        } else
        {
            // you get nothing! GOOD DAY SIR!
        }
    } //  <---- Note the curly bracket that is here!
          the hostess has delivered the information 
          to the captain and goes to the next person
          on the plane (if she has not reached the 
          end of the plane)
    

Резюме

Другими словами, что-то исчисляется, если у него есть счетчик . И счетчик должен (в основном): (i) помнить свое место ( состояние ), (ii) быть в состоянии двигаться дальше , (iii) и знать о текущем человеке, с которым он имеет дело.

Enumerable - это просто причудливое слово для «счетного». Другими словами, перечислимое позволяет вам «перечислять» (т.е. считать).

BKSpurgeon
источник
23

IEnumerable реализует GetEnumerator. При вызове этот метод возвращает IEnumerator, который реализует MoveNext, Reset и Current.

Таким образом, когда ваш класс реализует IEnumerable, вы говорите, что можете вызвать метод (GetEnumerator) и получить новый возвращенный объект (IEnumerator), который вы можете использовать в цикле, таком как foreach.

DavGarcia
источник
18

Реализация IEnumerable позволяет вам получить IEnumerator для списка.

IEnumerator допускает последовательный доступ к элементам списка в стиле foreach, используя ключевое слово yield.

До реализации foreach (например, в Java 1.4) способ итерации списка состоял в том, чтобы получить перечислитель из списка, а затем запросить у него «следующий» элемент в списке, пока значение возвращается как следующее Элемент не является нулевым. Foreach просто делает это неявно в качестве языковой функции, точно так же, как lock () реализует класс Monitor за кулисами.

Я ожидаю, что foreach работает со списками, потому что они реализуют IEnumerable.

Нил Барнвелл
источник
если это для списка, почему я не могу просто использовать foreach?
prodev42
.Net duck вводит оператор foreach, но IEnumerable / IEnumerable <T> является подходящим способом сказать, что ваш класс может быть перечислен.
user7116
15
  • Объект, реализующий IEnumerable, позволяет другим посещать каждый из его элементов (перечислителем) .
  • Объект, реализующий IEnumerator - это выполнение итерации. Он зацикливается на перечисляемом объекте.

Думайте о перечисляемых объектах как о списках, стеках, деревьях.

Ливен Керсмакерс
источник
12

IEnumerable и IEnumerator (и их общие аналоги IEnumerable <T> и IEnumerator <T>) являются базовыми интерфейсами реализаций итераторов в коллекциях .Net Framework Class Libray .

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

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

IEnumerable

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

петля foreach

foreach (var value in list)
  Console.WriteLine(value);

Я думаю, что foreachцикл является одной из основных причин использования интерфейсов IEnumerable . foreachимеет очень сжатый синтаксис и очень прост для понимания по сравнению с классическим стилем C для циклов, где вам нужно проверять различные переменные, чтобы увидеть, что он делает.

дать ключевое слово

Вероятно, менее известная особенность в том , что IEnumerable также позволяет генераторы в C # с использованием yield returnи yield breakотчетностью.

IEnumerable<Thing> GetThings() {
   if (isNotReady) yield break;
   while (thereIsMore)
     yield return GetOneMoreThing();
}

Абстракции

Другим распространенным сценарием на практике является использование IEnumerable для предоставления минималистических абстракций. Поскольку это крошечный и доступный только для чтения интерфейс, рекомендуется представлять свои коллекции как IEnumerable (а не List, например). Таким образом, вы можете свободно изменять свою реализацию, не нарушая код вашего клиента (например, измените List на LinkedList ).

Попался

Следует помнить о том, что при реализации потоковой передачи (например, извлечение данных строка за строкой из базы данных вместо загрузки сначала всех результатов в память) вы не можете перебирать коллекцию более одного раза. Это отличается от коллекций в памяти, таких как List , где вы можете выполнять многократные итерации без проблем. ReSharper, например, имеет проверку кода для возможного множественного перечисления IEnumerable .

IEnumerator

IEnumerator, с другой стороны, является скрытым интерфейсом, который заставляет IEnumerble-foreach-magic работать. Строго говоря, он допускает явные итераторы.

var iter = list.GetEnumerator();
while (iter.MoveNext())
    Console.WriteLine(iter.Current);

По моему опыту, IEnumerator редко используется в распространенных сценариях из-за его более многословного синтаксиса и немного сбивающей с толку семантики (по крайней мере для меня; например, MoveNext () также возвращает значение, которое имя не предлагает вообще).

Вариант использования для IEnumerator

Я использовал только IEnumerator, в частности (немного более низкого уровня) библиотеки и платформы, где я предоставлял интерфейсы IEnumerable . Одним из примеров является библиотека обработки потока данных, которая предоставляла серии объектов в foreachцикле, даже если за кадром данные собирались с использованием различных файловых потоков и сериализаций.

Код клиента

foreach(var item in feed.GetItems())
    Console.WriteLine(item);

Библиотека

IEnumerable GetItems() {
    return new FeedIterator(_fileNames)
}

class FeedIterator: IEnumerable {
    IEnumerator GetEnumerator() {
        return new FeedExplicitIterator(_stream);
    }
}

class FeedExplicitIterator: IEnumerator {
    DataItem _current;

    bool MoveNext() {
        _current = ReadMoreFromStream();
        return _current != null;           
    }

    DataItem Current() {
        return _current;   
    }
}
Зия
источник
9

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

IEnumeratorфактический объект, используемый для выполнения итераций. Он контролирует перемещение от одного объекта к другому в списке.

Большую часть времени IEnumerable& IEnumeratorпрозрачно используются как часть foreachцикла.

Дэн Герберт
источник
6

Различия между IEnumerable и IEnumerator:

  • IEnumerable использует IEnumerator для внутреннего использования.
  • IEnumerable не знает, какой элемент / объект выполняется.
  • Всякий раз, когда мы передаем IEnumerator другой функции, он знает текущую позицию элемента / объекта.
  • Всякий раз, когда мы передаем коллекцию IEnumerable другой функции, она не знает текущей позиции элемента / объекта (не знает, какой элемент ее выполняет)

    IEnumerable имеет один метод GetEnumerator ()

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

IEnumerator имеет одно свойство с именем Current и два метода, Reset () и MoveNext () (которые полезны для определения текущей позиции элемента в списке).

public interface IEnumerator
{
     object Current { get; }
     bool MoveNext();
     void Reset();
}
Аджай
источник
5

IEnumerable - это блок, содержащий Ienumerator. IEnumerable является базовым интерфейсом для всех коллекций. Цикл foreach может работать, если коллекция реализует IEnumerable. В приведенном ниже коде объясняется, как создать собственный перечислитель. Давайте сначала определим наш класс, из которого мы собираемся сделать коллекцию.

public class Customer
{
    public String Name { get; set; }
    public String City { get; set; }
    public long Mobile { get; set; }
    public double Amount { get; set; }
}

Теперь мы определим класс, который будет действовать как коллекция для нашего класса Customer. Обратите внимание, что он реализует интерфейс IEnumerable. Так что нам нужно реализовать метод GetEnumerator. Это вернет наш пользовательский перечислитель.

public class CustomerList : IEnumerable
{
    Customer[] customers = new Customer[4];
    public CustomerList()
    {
        customers[0] = new Customer { Name = "Bijay Thapa", City = "LA", Mobile = 9841639665, Amount = 89.45 };
        customers[1] = new Customer { Name = "Jack", City = "NYC", Mobile = 9175869002, Amount = 426.00 };
        customers[2] = new Customer { Name = "Anil min", City = "Kathmandu", Mobile = 9173694005, Amount = 5896.20 };
        customers[3] = new Customer { Name = "Jim sin", City = "Delhi", Mobile = 64214556002, Amount = 596.20 };
    }

    public int Count()
    {
        return customers.Count();
    }
    public Customer this[int index]
    {
        get
        {
            return customers[index];
        }
    }
    public IEnumerator GetEnumerator()
    {
        return customers.GetEnumerator(); // we can do this but we are going to make our own Enumerator
        return new CustomerEnumerator(this);
    }
}

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

 public class CustomerEnumerator : IEnumerator
    {
        CustomerList coll;
        Customer CurrentCustomer;
        int currentIndex;
        public CustomerEnumerator(CustomerList customerList)
        {
            coll = customerList;
            currentIndex = -1;
        }

        public object Current => CurrentCustomer;

        public bool MoveNext()
        {
            if ((currentIndex++) >= coll.Count() - 1)
                return false;
            else
                CurrentCustomer = coll[currentIndex];
            return true;
        }

        public void Reset()
        {
            // we dont have to implement this method.
        }
    }

Теперь мы можем использовать цикл foreach над нашей коллекцией, как показано ниже;

    class EnumeratorExample
    {
        static void Main(String[] args)
        {

            CustomerList custList = new CustomerList();
            foreach (Customer cust in custList)
            {
                Console.WriteLine("Customer Name:"+cust.Name + " City Name:" + cust.City + " Mobile Number:" + cust.Amount);
            }
            Console.Read();

        }
    }
эмир
источник
4

Понимание шаблона итератора будет полезно для вас. Я рекомендую читать то же самое.

Шаблон итератора

На высоком уровне шаблон итератора может использоваться для обеспечения стандартного способа перебора коллекций любого типа. У нас есть 3 участника в шаблоне итератора, фактическая коллекция (клиент), агрегатор и итератор. Агрегат - это интерфейсный / абстрактный класс, который имеет метод, который возвращает итератор. Iterator - это интерфейсный / абстрактный класс, который имеет методы, позволяющие выполнять итерацию по коллекции.

Чтобы реализовать шаблон, нам сначала нужно реализовать итератор для создания конкретного объекта, который может перебирать соответствующую коллекцию (клиент). Затем коллекция (клиент) реализует агрегатор для возврата экземпляра вышеуказанного итератора.

Вот диаграмма UML Шаблон итератора

Таким образом, в основном в c # IEnumerable является абстрактным агрегатом, а IEnumerator - абстрактным итератором. IEnumerable имеет единственный метод GetEnumerator, который отвечает за создание экземпляра IEnumerator нужного типа. Коллекции, подобные спискам, реализуют IEnumerable.

Пример. Предположим, что у нас есть метод, getPermutations(inputString)который возвращает все перестановки строки, и что метод возвращает экземплярIEnumerable<string>

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

 int count = 0;
        var permutations = perm.getPermutations(inputString);
        foreach (string permutation in permutations)
        {
            count++;
        }

Компилятор c # более или менее преобразует вышеуказанное в

using (var permutationIterator = perm.getPermutations(input).GetEnumerator())
        {
            while (permutationIterator.MoveNext())
            {
                count++;
            }
        }

Если у вас есть какие-либо вопросы, пожалуйста, не стесняйтесь спрашивать.

lalatnayak
источник
2

Незначительный вклад.

Как многие из них объясняют, «когда использовать» и «использовать с foreach». Я подумал о том, чтобы добавить здесь другую разницу состояний, как было задано в вопросе о разнице между IEnumerable и IEnumerator.

Я создал приведенный ниже пример кода на основе обсуждений ниже.

IEnumerable, IEnumerator против foreach, когда использовать, в чем разница между IEnumerator и IEnumerable?

Enumerator сохраняет состояние (положение итерации) между вызовами функций, в то время как итерации другой стороны Enumerable не делает.

Вот проверенный пример с комментариями, чтобы понять.

Эксперты, пожалуйста, добавьте / исправьте меня.

static void EnumerableVsEnumeratorStateTest()
{
    IList<int> numList = new List<int>();

    numList.Add(1);
    numList.Add(2);
    numList.Add(3);
    numList.Add(4);
    numList.Add(5);
    numList.Add(6);

    Console.WriteLine("Using Enumerator - Remembers the state");
    IterateFrom1to3(numList.GetEnumerator());

    Console.WriteLine("Using Enumerable - Does not Remembers the state");
    IterateFrom1to3Eb(numList);

    Console.WriteLine("Using Enumerable - 2nd functions start from the item 1 in the collection");
}

static void IterateFrom1to3(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());

        if (numColl.Current > 3)
        {
            // This method called 3 times for 3 items (4,5,6) in the collection. 
            // It remembers the state and displays the continued values.
            IterateFrom3to6(numColl);
        }
    }
}

static void IterateFrom3to6(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());
    }
}

static void IterateFrom1to3Eb(IEnumerable<int> numColl)
{
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());

        if (num>= 5)
        {
            // The below method invokes for the last 2 items.
            //Since it doesnot persists the state it will displays entire collection 2 times.
            IterateFrom3to6Eb(numColl);
        }
    }
}

static void IterateFrom3to6Eb(IEnumerable<int> numColl)
{
    Console.WriteLine();
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());
    }
}
Sai
источник
2

Я заметил эти различия:

О. Мы повторяем список по-разному, foreach может использоваться для IEnumerable и цикл while для IEnumerator.

Б. IEnumerator может запомнить текущий индекс, когда мы переходим от одного метода к другому (он начинает работать с текущим индексом), но IEnumerable не может запомнить индекс и сбрасывает индекс до начала. Подробнее в этом видео https://www.youtube.com/watch?v=jd3yUjGc9M0

RotatingWheel
источник
1

IEnumerableи IEnumeratorоба являются интерфейсами в C #.

IEnumerableинтерфейс, определяющий единственный метод, GetEnumerator()который возвращает IEnumeratorинтерфейс

Это работает для доступа только для чтения к коллекции, которая реализуется, которая IEnumerableможет использоваться с foreachоператором.

IEnumeratorимеет два метода, MoveNextи Reset. У этого также есть свойство, названное Current.

Ниже показана реализация IEnumerable и IEnumerator.

Джихед Джаоиди
источник
0
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Enudemo
{

    class Person
    {
        string name = "";
        int roll;

        public Person(string name, int roll)
        {
            this.name = name;
            this.roll = roll;
        }

        public override string ToString()
        {
            return string.Format("Name : " + name + "\t Roll : " + roll);
        }

    }


    class Demo : IEnumerable
    {
        ArrayList list1 = new ArrayList();

        public Demo()
        {
            list1.Add(new Person("Shahriar", 332));
            list1.Add(new Person("Sujon", 333));
            list1.Add(new Person("Sumona", 334));
            list1.Add(new Person("Shakil", 335));
            list1.Add(new Person("Shruti", 336));
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
           return list1.GetEnumerator();
        }
    }



    class Program
    {
        static void Main(string[] args)
        {
            Demo d = new Demo();  // Notice here. it is simple object but for 
                                //IEnumerator you can get the collection data

            foreach (Person X in d)
            {
                Console.WriteLine(X);
            }

            Console.ReadKey();
        }
    }
}
/*
Output : 

Name : Shahriar  Roll : 332
Name : Sujon     Roll : 333
Name : Sumona    Roll : 334
Name : Shakil    Roll : 335
Name : Shruti    Roll : 336
  */
Д-р Шахриар
источник