我目前正在学习C#,目的是有效地使用Razor和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的原因。
非常感谢任何帮助,谢谢!
答案 0 :(得分:2)
首先,如果要创建自己的枚举器,则应该使类实现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集合中的每个项目。它们不是互斥的类,是依赖类。您通常不会像示例中那样创建一个枚举器来浏览您的值。您将创建一个集合并使用枚举器来导航它(或者在更高级别迭代使用幕后枚举器的集合)。
答案 1 :(得分:2)
这是在您的示例中实现枚举器模式的方式。我希望这澄清了一些事情,特别是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();
}
}
}
答案 2 :(得分:1)
C#编译器将其转换为:
foreach(string x in suits)
使用IEnumerator
(或IEnumerator<T>
)。
IEnumerable
和IEnumerable<T>
接口定义了GetEnumerator
方法,该方法分别返回IEnumerator
(或IEnumerator<T>
),该方法用于您正在使用foreach
进行迭代。
异常是使用数组进行迭代,编译器对此进行不同的处理(感谢@Jon Skeet)。
答案 3 :(得分:1)
您可能(通常会)必须执行一些更复杂的操作,而不仅仅是打印出对象的值。
您的类可能必须逐个返回(yield)对象以进行某些外部处理(通过其他类,方法等)。
然后公开IEnumerator
比返回整个集合更好,因为枚举意味着你当时只传递一个对象!不是一列(可能)一个百万元素。
答案 4 :(得分:1)
这很好,因为您的代码依赖于接口(IEnumerable
)
今天代码中的套装类型是Array
private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };
如果你决定使用for循环,你的代码看起来或多或少就像下面的
for (int index = 0; index < suits.Length; suits++)
{
// code here
}
明年,您可能有理由将其类型从Array
更改为List<T>
。如果您使用,则需要更新代码块,因为Array具有Length
而List具有Count
属性。
答案 5 :(得分:0)
如果你看一下System.Array,你会发现Array实现了IEnumerable。 而且每个都不需要IEnumerable对象。它只需要一个名为GetEnumerator的方法。
答案 6 :(得分:0)
假设您要创建一个自定义的套装集合......学习如何实现IEnumerable<T>
将会让您对它为何如此有用有所了解。没有它,LINQ就不会像我们所知的那样存在。