Может кто-нибудь объяснить мне IEnumerable и IEnumerator? - PullRequest
237 голосов
/ 17 февраля 2009

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

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

Ответы [ 16 ]

4 голосов
/ 20 октября 2016

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

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

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

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

Вот диаграмма UML Iterator Pattern

Таким образом, в основном в 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++;
            }
        }

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

3 голосов
/ 05 мая 2019

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();

        }
    }
2 голосов
/ 27 июля 2015

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

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

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

2 голосов
/ 28 апреля 2014

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

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

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

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

Перечислитель сохраняет состояние (положение итерации) между вызовами функций, в то время как итерации, с другой стороны, не перечисляются 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());
    }
}
1 голос
/ 13 апреля 2019

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

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

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

IEnumerator имеет два метода, MoveNext и Reset. Он также имеет свойство под названием Current.

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

0 голосов
/ 02 ноября 2017
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
  */
...