有人能给我解释一下IEnumerable和IEnumerator吗?

例如,什么时候用它胜过foreach?IEnumerable和IEnumerator的区别是什么?为什么我们需要使用它?


当前回答

理解Iterator模式将对您有所帮助。我建议你也读一下。

迭代器模式

在高层次上,迭代器模式可用于提供一种遍历任何类型集合的标准方法。 迭代器模式中有3个参与者,实际的集合(客户端)、聚合器和迭代器。聚合是一个接口/抽象类,具有返回迭代器的方法。Iterator是一个接口/抽象类,它具有允许我们遍历集合的方法。

为了实现该模式,我们首先需要实现一个迭代器来生成一个具体的迭代器,该迭代器可以遍历相关的集合(客户端) 然后集合(客户端)实现聚合器以返回上述迭代器的实例。

下面是UML图

在c#中,IEnumerable是抽象的集合IEnumerator是抽象的迭代器。IEnumerable有一个单独的方法GetEnumerator,它负责创建所需类型的IEnumerator实例。像list这样的集合实现了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++;
            }
        }

如果你有任何问题,请尽管问。

其他回答

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

IEnumerable和IEnumerator都是c#中的接口。

IEnumerable是一个接口,它定义了一个返回IEnumerator接口的方法GetEnumerator()。

这适用于对集合的只读访问,该集合实现了IEnumerable可与foreach语句一起使用。

IEnumerator有两个方法,MoveNext和Reset。它还有一个名为Current的属性。

下面展示了IEnumerable和IEnumerator的实现。

实现IEnumerable可以让你获得一个列表的IEnumerator。

IEnumerator允许使用yield关键字以foreach样式顺序访问列表中的项。

在foreach实现之前(例如在Java 1.4中),迭代列表的方法是从列表中获取一个枚举器,然后向它请求列表中的“下一个”项,只要作为下一个项返回的值不为空。Foreach只是隐式地将其作为一种语言特性来实现,与lock()在幕后实现Monitor类的方式相同。

我期望foreach工作在列表上,因为它们实现了IEnumerable。

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
  */

IEnumerable是一个包含Ienumerator的框。IEnumerable是所有集合的基本接口。如果集合实现了IEnumerable,则foreach循环可以运行。在下面的代码中,它解释了拥有自己的枚举器的步骤。让我们首先定义我们要创建集合的Class。

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

现在我们将定义Class,它将作为我们的类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();

        }
    }