有人能给我解释一下IEnumerable和IEnumerator吗?
例如,什么时候用它胜过foreach?IEnumerable和IEnumerator的区别是什么?为什么我们需要使用它?
有人能给我解释一下IEnumerable和IEnumerator吗?
例如,什么时候用它胜过foreach?IEnumerable和IEnumerator的区别是什么?为什么我们需要使用它?
当前回答
实现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被透明地用作foreach循环的一部分。
IEnumerable和IEnumerator都是c#中的接口。
IEnumerable是一个接口,它定义了一个返回IEnumerator接口的方法GetEnumerator()。
这适用于对集合的只读访问,该集合实现了IEnumerable可与foreach语句一起使用。
IEnumerator有两个方法,MoveNext和Reset。它还有一个名为Current的属性。
下面展示了IEnumerable和IEnumerator的实现。
小贡献。
正如他们中的许多人解释“何时使用”和“与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());
}
}
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
*/