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

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


当前回答

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

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

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

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

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

其他回答

IEnumerable和IEnumerator(以及它们的泛型对应物IEnumerable<T>和IEnumerator<T>)是. net Framework类库集合中迭代器实现的基本接口。

IEnumerable是大多数代码中最常见的接口。它支持foreach循环,生成器(考虑yield),由于它的小接口,它被用于创建紧密的抽象。IEnumerable依赖于IEnumerator。

另一方面,IEnumerator提供了一个稍低级别的迭代接口。它被称为显式迭代器,使程序员能够更好地控制迭代周期。

IEnumerable

IEnumerable是一个标准接口,支持对支持它的集合进行迭代(事实上,我现在能想到的所有集合类型都实现了IEnumerable)。编译器支持允许像foreach这样的语言特性。一般来说,它支持这个隐式迭代器实现。

foreach循环

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

我认为foreach循环是使用IEnumerable接口的主要原因之一。foreach的语法非常简洁,与经典C风格的for循环相比非常容易理解,在经典C风格的for循环中,您需要检查各种变量来查看它在做什么。

生成的关键字

可能一个不太为人所知的特性是IEnumerable还通过使用yield return和yield break语句支持c#中的生成器。

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

抽象

实践中的另一个常见场景是使用IEnumerable来提供极简抽象。因为它是一个很小的只读接口,所以建议将集合公开为IEnumerable(而不是List)。这样你就可以在不破坏客户端代码的情况下自由更改实现(例如将List更改为LinkedList)。

问题

需要注意的一种行为是,在流实现中(例如,从数据库中逐行检索数据,而不是首先将所有结果加载到内存中),您不能对集合进行多次迭代。这与List之类的内存集合相反,在List中可以迭代多次而不会出现问题。例如,ReSharper对IEnumerable的可能多个枚举进行了代码检查。

分子

另一方面,IEnumerator是使ienumble -foreach-magic工作的幕后接口。严格来说,它启用了显式迭代器。

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

根据我的经验,IEnumerator很少在常见场景中使用,因为它的语法比较冗长,语义有点混乱(至少对我来说是这样;例如,MoveNext()也返回一个值,这个名称根本不建议)。

IEnumerator的用例

我只在提供IEnumerable接口的库和框架中使用IEnumerator(级别稍低)。一个例子是数据流处理库,它在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;   
    }
}

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实现了GetEnumerator。当调用时,该方法将返回一个IEnumerator,它实现了MoveNext, Reset和Current。

因此,当你的类实现IEnumerable时,你是在说你可以调用一个方法(GetEnumerator)并返回一个新的对象(一个IEnumerator),你可以在循环中使用,比如foreach。

小贡献。

正如他们中的许多人解释“何时使用”和“与foreach一起使用”。 我想在这里添加另一个状态差异,以询问IEnumerable和IEnumerator之间的差异。

我根据下面的讨论线程创建了下面的代码示例。

IEnumerable, IEnumerator vs 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());
    }
}

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

        }
    }