有人能给我解释一下IEnumerable和IEnumerator吗?
例如,什么时候用它胜过foreach?IEnumerable和IEnumerator的区别是什么?为什么我们需要使用它?
有人能给我解释一下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();
}
}