C# 任何人都可以向我解释 IEnumerable 和 IEnumerator 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/558304/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can anyone explain IEnumerable and IEnumerator to me?
提问by prodev42
Can anyone explain IEnumerable and IEnumerator to me?
任何人都可以向我解释 IEnumerable 和 IEnumerator 吗?
for example, when to use it over foreach? what's the difference between IEnumerable and IEnumerator? Why do we need to use it?
例如,什么时候在 foreach 上使用它?IEnumerable 和 IEnumerator 有什么区别?为什么我们需要使用它?
采纳答案by Robert Rossney
for example, when to use it over foreach?
例如,什么时候在 foreach 上使用它?
You don't use IEnumerable
"over" foreach
. Implementing IEnumerable
makes using foreach
possible.
你不使用IEnumerable
"over" foreach
。实施IEnumerable
使使用成为foreach
可能。
When you write code like:
当您编写如下代码时:
foreach (Foo bar in baz)
{
...
}
it's functionally equivalent to writing:
它在功能上等同于编写:
IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
bar = (Foo)bat.Current
...
}
By "functionally equivalent," I mean that's actually what the compiler turns the code into. You can't use foreach
on baz
in this example unlessbaz
implements IEnumerable
.
通过“功能等效”,我的意思是这实际上是编译器将代码转换成的内容。在这个例子中你不能使用foreach
on baz
,除非baz
实现了IEnumerable
。
IEnumerable
means that baz
implements the method
IEnumerable
表示baz
实现方法
IEnumerator GetEnumerator()
The IEnumerator
object that this method returns must implement the methods
IEnumerator
此方法返回的对象必须实现这些方法
bool MoveNext()
and
和
Object Current()
The first method advances to the next object in the IEnumerable
object that created the enumerator, returning false
if it's done, and the second returns the current object.
第一个方法前进到IEnumerable
创建枚举器的对象中的下一个对象,false
如果完成则返回,第二个方法返回当前对象。
Anything in .Net that you can iterate over implements IEnumerable
. If you're building your own class, and it doesn't already inherit from a class that implements IEnumerable
, you can make your class usable in foreach
statements by implementing IEnumerable
(and by creating an enumerator class that its new GetEnumerator
method will return).
.Net 中可以迭代的任何东西都可以实现IEnumerable
。如果您正在构建自己的类,并且它尚未从实现 的类继承IEnumerable
,则可以foreach
通过实现IEnumerable
(并通过创建其新GetEnumerator
方法将返回的枚举器类)使您的类在语句中可用。
回答by Neil Barnwell
Implementing IEnumerable enables you to get an IEnumerator for a list.
实现 IEnumerable 使您可以获得列表的 IEnumerator。
IEnumerator allows foreach style sequential access to the items in the list, using the yield keyword.
IEnumerator 允许 foreach 样式使用 yield 关键字对列表中的项目进行顺序访问。
Before foreach implementation (in Java 1.4, for example), the way to iterate a list was to get an enumerator from the list, then ask it for the "next" item in the list, for as long as the value returned as the next item is not null. Foreach simply does that implicitly as a language feature, in the same way that lock() implements the Monitor class behind the scenes.
在 foreach 实现之前(例如在 Java 1.4 中),迭代列表的方法是从列表中获取一个枚举器,然后向它询问列表中的“下一个”项目,只要返回的值作为下一个项目不为空。Foreach 只是作为一种语言功能隐式地执行此操作,就像 lock() 在幕后实现 Monitor 类一样。
I expect foreach works on lists because they implement IEnumerable.
我希望 foreach 在列表上工作,因为它们实现了 IEnumerable。
回答by core
Implementing IEnumerable means your class returns an IEnumerator object:
实现 IEnumerable 意味着您的类返回一个 IEnumerator 对象:
public class People : IEnumerable
{
IEnumerator IEnumerable.GetEnumerator()
{
// return a PeopleEnumerator
}
}
Implementing IEnumerator means your class returns the methods and properties for iteration:
实现 IEnumerator 意味着您的类返回迭代的方法和属性:
public class PeopleEnumerator : IEnumerator
{
public void Reset()...
public bool MoveNext()...
public object Current...
}
That's the difference anyway.
反正这就是区别。
回答by Lieven Keersmaekers
- An object implementing IEnumerableallows others to visit each of its items (by an enumerator).
- An object implementing IEnumeratoris the doing the iteration. It's looping over an enumerable object.
- 实现IEnumerable的对象允许其他人访问它的每个项目(通过枚举器)。
- 实现IEnumerator的对象正在执行迭代。它在一个可枚举的对象上循环。
Think of enumerable objects as of lists, stacks, trees.
将可枚举对象视为列表、堆栈、树。
回答by Dan Herbert
Implementing IEnumerable
essentially means that the object can be iterated over. This doesn't necessarily mean it is an array as there are certain lists that can't be indexed but you can enumerate them.
实现IEnumerable
本质上意味着可以迭代对象。这并不一定意味着它是一个数组,因为某些列表无法编入索引,但您可以枚举它们。
IEnumerator
is the actual object used to perform the iterations. It controls moving from one object to the next in the list.
IEnumerator
是用于执行迭代的实际对象。它控制从一个对象移动到列表中的下一个对象。
Most of the time, IEnumerable
& IEnumerator
are used transparently as part of a foreach
loop.
大多数情况下,IEnumerable
&IEnumerator
被透明地用作foreach
循环的一部分。
回答by DavGarcia
IEnumerableimplements GetEnumerator. When called, that method will return an IEnumeratorwhich implements MoveNext, Reset and Current.
IEnumerable实现了 GetEnumerator。调用时,该方法将返回一个实现 MoveNext、Reset 和 Current的IEnumerator。
Thus when your class implements IEnumerable, you are saying that you can call a method (GetEnumerator) and get a new object returned (an IEnumerator) you can use in a loop such as foreach.
因此,当您的类实现 IEnumerable 时,您是说您可以调用一个方法 (GetEnumerator) 并返回一个新对象(一个 IEnumerator),您可以在诸如 foreach 之类的循环中使用。
回答by Sai
A Minor contribution.
次要贡献。
As many of them explain about 'when to use' and 'use with foreach'. I thought of adding Another States Differencehere as requested in question about the difference between both IEnumerable an IEnumerator.
正如他们中的许多人所解释的“何时使用”和“与 foreach 一起使用”。我想根据有关 IEnumerable 和 IEnumerator 之间差异的问题,在此处添加另一个状态差异。
I created the below code sample based on the below discussion threads.
我根据以下讨论线程创建了以下代码示例。
IEnumerable , IEnumerator vs foreach, when to use whatWhat is the difference between IEnumerator and IEnumerable?
IEnumerable , IEnumerator vs foreach, 什么时候使用IEnumerator 和 IEnumerable有什么区别?
Enumerator preserves the state (iteration position) between function calls while iterations the other hand Enumerable does not.
Enumerator 保留函数调用之间的状态(迭代位置),而迭代 Enumerable 则不会。
Here is the tested example with comments to understand.
这是经过测试的示例,带有注释以供理解。
Experts please add/correct me.
专家请补充/纠正我。
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());
}
}
回答by Said Roohullah Allem
The IEnumerable and IEnumerator Interfaces
IEnumerable 和 IEnumerator 接口
To begin examining the process of implementing existing .NET interfaces, let's first look at the role of IEnumerable and IEnumerator. Recall that C# supports a keyword named foreach that allows you to iterate over the contents of any array type:
要开始检查实现现有 .NET 接口的过程,让我们首先看看 IEnumerable 和 IEnumerator 的作用。回想一下,C# 支持名为 foreach 的关键字,它允许您迭代任何数组类型的内容:
// Iterate over an array of items.
int[] myArrayOfInts = {10, 20, 30, 40};
foreach(int i in myArrayOfInts)
{
Console.WriteLine(i);
}
While it might seem that only array types can make use of this construct, the truth of the matter is any type supporting a method named GetEnumerator() can be evaluated by the foreach construct.To illustrate, follow me!
虽然似乎只有数组类型可以使用此构造,但事实是任何支持名为 GetEnumerator() 的方法的类型都可以由 foreach 构造求值。为了说明,请跟我来!
Suppose we have a Garage class:
假设我们有一个 Garage 类:
// Garage contains a set of Car objects.
public class Garage
{
private Car[] carArray = new Car[4];
// Fill with some Car objects upon startup.
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
}
Ideally, it would be convenient to iterate over the Garage object's subitems using the foreach construct, just like an array of data values:
理想情况下,使用 foreach 构造迭代 Garage 对象的子项会很方便,就像数据值数组一样:
// This seems reasonable ...
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
Garage carLot = new Garage();
// Hand over each car in the collection?
foreach (Car c in carLot)
{
Console.WriteLine("{0} is going {1} MPH",
c.PetName, c.CurrentSpeed);
}
Console.ReadLine();
}
}
Sadly, the compiler informs you that the Garage class does not implement a method named GetEnumerator(). This method is formalized by the IEnumerable interface, which is found lurking within the System.Collections namespace. Classes or structures that support this behavior advertise that they are able to expose contained subitems to the caller (in this example, the foreach keyword itself). Here is the definition of this standard .NET interface:
遗憾的是,编译器会通知您 Garage 类没有实现名为 GetEnumerator() 的方法。此方法由 IEnumerable 接口形式化,该接口隐藏在 System.Collections 命名空间中。支持此行为的类或结构声明它们能够向调用者公开包含的子项(在本例中,是 foreach 关键字本身)。下面是这个标准 .NET 接口的定义:
// This interface informs the caller
// that the object's subitems can be enumerated.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
As you can see, the GetEnumerator() method returns a reference to yet another interface named System.Collections.IEnumerator. This interface provides the infrastructure to allow the caller to traverse the internal objects contained by the IEnumerable-compatible container:
如您所见,GetEnumerator() 方法返回对另一个名为 System.Collections.IEnumerator 的接口的引用。此接口提供基础结构以允许调用者遍历 IEnumerable 兼容容器包含的内部对象:
// This interface allows the caller to
// obtain a container's subitems.
public interface IEnumerator
{
bool MoveNext (); // Advance the internal position of the cursor.
object Current { get;} // Get the current item (read-only property).
void Reset (); // Reset the cursor before the first member.
}
If you want to update the Garage type to support these interfaces, you could take the long road and implement each method manually. While you are certainly free to provide customized versions of GetEnumerator(), MoveNext(), Current, and Reset(), there is a simpler way. As the System.Array type (as well as many other collection classes) already implements IEnumerable and IEnumerator, you can simply delegate the request to the System.Array as follows:
如果您想更新 Garage 类型以支持这些接口,您可以走很长的路并手动实现每个方法。虽然您当然可以自由提供 GetEnumerator()、MoveNext()、Current 和 Reset() 的自定义版本,但还有一种更简单的方法。由于 System.Array 类型(以及许多其他集合类)已经实现了 IEnumerable 和 IEnumerator,您可以简单地将请求委托给 System.Array,如下所示:
using System.Collections;
...
public class Garage : IEnumerable
{
// System.Array already implements IEnumerator!
private Car[] carArray = new Car[4];
public Garage()
{
carArray[0] = new Car("FeeFee", 200);
carArray[1] = new Car("Clunker", 90);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
public IEnumerator GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
}
After you have updated your Garage type, you can safely use the type within the C# foreach construct. Furthermore, given that the GetEnumerator() method has been defined publicly, the object user could also interact with the IEnumerator type:
更新 Garage 类型后,您可以安全地在 C# foreach 构造中使用该类型。此外,鉴于 GetEnumerator() 方法已公开定义,对象用户还可以与 IEnumerator 类型交互:
// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);
However, if you prefer to hide the functionality of IEnumerable from the object level, simply make use of explicit interface implementation:
但是,如果您更喜欢从对象级别隐藏 IEnumerable 的功能,只需使用显式接口实现:
IEnumerator IEnumerable.GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
By doing so, the casual object user will not find the Garage's GetEnumerator() method, while the foreach construct will obtain the interface in the background when necessary.
通过这样做,临时对象用户将找不到 Garage 的 GetEnumerator() 方法,而 foreach 构造将在必要时在后台获取接口。
Adapted from the Pro C# 5.0 and the .NET 4.5 Framework
回答by Ajay
Differences between IEnumerable and IEnumerator :
IEnumerable 和 IEnumerator 的区别:
- IEnumerable uses IEnumerator internally.
- IEnumerable doesn't know which item/object is executing.
- Whenever we pass IEnumerator to another function, it knows the current position of item/object.
Whenever we pass an IEnumerable collection to another function, it doesn't know the current position of item/object (doesn't know which item its executing)
IEnumerable have one method GetEnumerator()
- IEnumerable 在内部使用 IEnumerator。
- IEnumerable 不知道正在执行哪个项目/对象。
- 每当我们将 IEnumerator 传递给另一个函数时,它就知道项目/对象的当前位置。
每当我们将一个 IEnumerable 集合传递给另一个函数时,它不知道项目/对象的当前位置(不知道它正在执行哪个项目)
IEnumerable 有一个方法 GetEnumerator()
public interface IEnumerable<out T> : IEnumerable { IEnumerator<T> GetEnumerator(); }
public interface IEnumerable<out T> : IEnumerable { IEnumerator<T> GetEnumerator(); }
IEnumerator has one property called Current and two methods, Reset() and MoveNext() (which is useful for knowing the current position of an item in a list).
IEnumerator 有一个名为 Current 的属性和两个方法,即 Reset() 和 MoveNext()(这对于了解列表中项目的当前位置很有用)。
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
回答by RotatingWheel
I have noticed these differences:
我注意到了这些差异:
A. We iterate the list in different way, foreach can be used for IEnumerable and while loop for IEnumerator.
A. 我们以不同的方式迭代列表,foreach 可用于 IEnumerable,而 while 循环可用于 IEnumerator。
B. IEnumerator can remember the current index when we pass from one method to another (it start working with current index) but IEnumerable can't remember the index and it reset the index to beginning. More in this video https://www.youtube.com/watch?v=jd3yUjGc9M0
B. 当我们从一种方法传递到另一种方法时,IEnumerator 可以记住当前索引(它开始使用当前索引)但 IEnumerable 无法记住索引并且它将索引重置为开始。更多视频https://www.youtube.com/watch?v=jd3yUjGc9M0