理解IEnumerator有困难
本文关键字:IEnumerator 理解 | 更新日期: 2023-09-27 18:13:32
我目前正在学习c#,目的是有效地使用ingrazor和Umbraco,我有一点PHP背景和JavaScript的合理知识。
我遇到了IEnumerator
接口,并且很难理解它。我在下面设置了一个代码片段来演示使用foreach:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace cardEnum
{
class suitsEnumerator
{
private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };
public void showAll()
{
foreach(string x in suits){
System.Console.WriteLine(x);
}
}
}
class run
{
static void Main()
{
Console.WriteLine("The suits are:");
var suits = new suitsEnumerator();
suits.showAll();
Console.ReadKey();
}
}
}
有人可以解释为什么我甚至需要使用IEnumerator
时,我可以很容易地通过数组循环。我知道这是一个如此简单的问题,我只是想不出使用IEnumerable的理由。
任何帮助都将非常感激,谢谢!
这就是枚举器模式在您的示例中的实现方式。我希望这能澄清一些事情,特别是IEnumerable
和IEnumerator
之间的关系:
namespace cardEnum {
// simple manual enumerator
class SuitsEnumerator : IEnumerator {
private int pos = -1;
private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };
public object Current {
get { return suits[pos]; }
}
public bool MoveNext() {
pos++;
return (pos < suits.Length);
}
public void Reset() {
pos = -1;
}
}
class Suits : IEnumerable {
public IEnumerator GetEnumerator() {
return new SuitsEnumerator();
}
}
class run {
static void Main() {
Console.WriteLine("The suits are:");
var suits = new Suits();
foreach (var suit in suits) {
Console.WriteLine(suit);
}
Console.ReadKey();
}
}
}
当然,这是一个人为的例子来帮助理解。既然string[]
已经实现了IEnumerable
,就没有理由重新发明轮子了。
由于c#支持yields
关键字,最近创建枚举器变得简单了一些:
namespace cardEnum {
// no explicit SuitsEnumerator required
class Suits : IEnumerable {
public IEnumerator GetEnumerator() {
yield return "Hearts";
yield return "Spades";
yield return "Diamonds";
yield return "Clubs";
}
}
class run {
static void Main() {
Console.WriteLine("The suits are:");
var suits = new Suits();
foreach (var suit in suits) {
Console.WriteLine(suit);
}
Console.ReadKey();
}
}
}
首先,如果你要创建你自己的枚举器,你应该让类实现IEnumerator接口(或它的泛型等价)。
public class FooEnumerator : IEnumerator
{
#region IEnumerator Members
public object Current
{
get { throw new NotImplementedException(); }
}
public bool MoveNext()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
#endregion
}
枚举数通常用于在集合中每次移动一个项。这是一个简单的接口,用于支持移动的项目,但不表示项目本身。它只有当前项目和移动到下一个项目的概念。
另一方面,IEnumerable用于表示项的集合。IEnumerable根据其定义返回一个枚举数,其目的是枚举IEnumerable集合中的每个项。它们不是互斥类,它们是依赖类。
您通常不会像在示例中那样创建枚举器来遍历您的值。您将创建一个集合并使用枚举数来导航它(或者在更高的级别上迭代在幕后使用枚举数的集合)。
除了打印对象的值之外,您可能(而且经常)需要执行一些更复杂的操作。
你的类可能不得不一个接一个地返回(生成)对象以进行一些外部处理(由其他类、方法等)。
那么暴露IEnumerator
比返回整个集合要好,因为枚举意味着一次只传递一个对象!
c#编译器将此转换为
foreach(string x in suits)
使用IEnumerator
(或IEnumerator<T>
)。
IEnumerable
和IEnumerable<T>
接口定义了一个GetEnumerator
方法,该方法返回一个IEnumerator
(或分别为IEnumerator<T>
),这是您正在使用foreach
进行迭代所使用的。
例外是对数组进行迭代,编译器对数组的处理方式不同(感谢@Jon Skeet)。
这很好,因为你的代码依赖于接口(IEnumerable
)
今天的西服类型在你的代码是Array
private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };
如果你决定使用for循环,你的代码看起来或多或少像下面的
for (int index = 0; index < suits.Length; suits++)
{
// code here
}
明年您可能有理由将其类型从Array
更改为List<T>
。如果你使用for,你需要更新代码块,因为数组有Length
,而列表有Count
属性。
如果你看看System。你会看到Array实现了IEnumerable。每个都不需要IEnumerable对象。它只需要一个名为GetEnumerator的方法
假设您要创建一个自定义套装集合…学习如何实现IEnumerable<T>
将给你一点洞察为什么它是如此有用。没有它,LINQ就不可能存在。