02011901 枚举器和迭代器01-枚举器(IEnumerator)、可枚举类型(IEnumerable)、泛型枚举接口
02011901 枚举器和迭代器01-枚举器(IEnumerator)、可枚举类型(IEnumerable)、泛型枚举接口
1. 枚举器和可枚举类型
1.1 什么是枚举器
// 使用foreach语句读取数组中每一个元素
using System;
namespace Demo01
{
class Program
{
static void Main()
{
int[] arr = { 10, 20, 30, 40 };
foreach(int item in arr)
Console.WriteLine($"{item}");
Console.ReadLine();
}
}
}
控制台输出:
10
20
30
40
注意,数组能使用循环遍历的原因:
1. 数组可以按需提供一个叫做枚举器的对象。
2. 枚举器可以依次返回请求的数组中的元素。
3. 枚举器知道项的次序并且跟踪它在序列中的位置,然后返回请求的当前项。
1.2 可枚举类型

- 对于有枚举器的类型而言,必须有一种方法来获取它。获取枚举器的方法是调用对象的GetEnumerator方法。实现GetEnumerator方法的类型叫做可枚举类型。
- 可枚举类型 → 是带有GetEnumerator方法的类型,它返回用于项的枚举器。
- 枚举器 → 是可以依次返回集合中项的类对象。
1.3 foreach结构设计
- foreach结构设计用来和可枚举类型一起使用,只要给它的遍历对象是可枚举类型,比如数组,它就会执行如下行为。
- 通过调用GetEnumerator方法获取可枚举类型的枚举器。
- 从枚举器中请求每一项并且把它作为迭代变量,代码可以读取该变量但不可以改变。
必须是可枚举类型
↓
foreach(Type VarName in EnumerableObject)
2. IEnumerator接口
- 实现了IEnumerator接口的枚举器包含3个函数成员。
- Current → 返回序列中当前位置项的属性。
- 它是只读属性
- 它返回object类型的引用,所以可以返回任何类型的对象。
- MoveNext → 是把枚举器位置前进到集合中下一项的方法,它返回布尔值,指示新的位置是有效位置还是已经超过了序列的尾部。
- 如果新的位置是有效的,方法返回true。
- 如果新的位置是无效的(比如当前位置到达了尾部),方法返回false。
- 枚举器的原始位置在序列中的第一项之前,因此MoveNext必须在第一次使用Current之前调用。
- Reset → 是把位置重置为原始状态的方法。
- Current → 返回序列中当前位置项的属性。
3. IEnumerable接口
- 可枚举类是指实现了IEnumerable接口的类。
- IEnumerable接口只有一个成员,即GetEnumerator方法,它返回对象的枚举器。

GetEnumerator方法返回类的一个枚举器对象
// 如上图所示,演示了一个有3个枚举项的类MyClass,通过实现GetEnumerator方法来实现IEnumerable接口。
using System.Collections;
实现IEnumerable接口
↓
class MyClass : IEnumerable
{
public IEnumerator GetEnumerator {...}
↑
返回IEnumerator类型的对象
...
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 一个可枚举类的示例
using System.Collections;
class MyColors : IEnumerable
{
string[] Colors = {"Red", "Yellow", "Blue"};
public IEnumerator GetEnumerator()
{
return new ColorEnumerator(Colors);
↑
枚举器类的实例
}
}
4. 使用IEnumerable和IEnumerator的示例
using System;
using System.Collections;
namespace Demo01
{
class ColorEnumerator : IEnumerator // @1 通过实现IEnumerator接口,定义一个枚举器类型。
{
string[] colors;
int position = -1;
public ColorEnumerator(string[] theColors) // @1.1 构造函数传入一个string类型的数组。
{
colors = new string[theColors.Length];
for(int i = 0; i < theColors.Length; i++)
colors[i] = theColors[i]; // @1.2 将传入的数组每个元素添加到新数组当中。
}
public object Current // @1.4 实现IEnumerator接口只读的属性。
{
get
{
if(position == -1)
throw new InvalidCastException();
if (position >= colors.Length)
throw new InvalidOperationException();
return colors[position];
}
}
public bool MoveNext() // @1.3 实现IEnumerator接口的方法,MoveNext在第一次使用Current之前调用。
{
if (position < colors.Length - 1)
{
position++;
return true;
}
else
return false;
}
public void Reset() // @1.5 实现IEnumerator接口的方法。
{
position = -1;
}
}
class Spectrum : IEnumerable // @2 实现IEnumerable接口,定义一个可枚举类型。
{
string[] Colors = { "Violet", "Blue", "Green", "Yellow", "Orange" };
public IEnumerator GetEnumerator() // @2.1 注意,返回类型为接口。此时可以返回实现该接口类型的对象。
{
return new ColorEnumerator(Colors); // @2.2 返回ColorEnumerator类型的对象。
}
}
class Program
{
static void Main()
{
Spectrum st = new Spectrum();
foreach(string color in st) // @3 注意,st必须是可枚举类型。
Console.WriteLine(color);
Console.ReadLine();
}
}
}
控制台输出:
Violet
Blue
Green
Yellow
Orange
说明:
1. 使用foreach时,会自动调用可枚举类型的GetEnumerator方法。
2. 在@1处定义的是一个枚举器类型。该类型实现了IEnumerator,并实现了三个方法,其中MoveNext方法必须在第一次使用Current方法之前调用。
3. 在@2处定义的是一个可枚举类型。该类型实现了IEnumerable接口,并且实现了该接口唯一的方法GetEnumerator。
5. 泛型枚举接口
-
目前我们描述的接口都是非泛型版本,实际上大多数情况下开发人员应该使用泛型版本的IEnumerable
和IEnumerator 。 -
IEnumerable、IEnumerator这两个接口泛型和非泛型版本的本质差别如下。
- 对于非泛型形式。
- IEnumerable接口的GetEnumerator方法返回实现IEnumerator的枚举器类实例。
- 实现IEnumerator的类实现了Current属性,它返回object类型的引用,然后我们必须把它转换为对象的实际类型。
- 泛型接口继承自非泛型接口,对于泛型接口形式。
- IEnumerable
接口的GetEnumerator方法返回实现IEnumator 的枚举类的实例。 - 实现IEnumerator
的类实现了Current属性,它返回实际类型的实例,而不是object基类的引用(※※※)。 - 这些是协变接口,所以它们的实际声明就是IEenumerable
和IEnumerator ,这意味着实现这些接口的对象可以是派生的类型。
- IEnumerable
- 对于非泛型形式。
-
需要注意的是,我们目前所看到的非泛型接口的实现不是类型安全的。它们返回object类型的引用,然后必须转换为实际类型。
-
而泛型接口的枚举器是类型安全的,它返回实际类型的引用。
-
如果要创建自己的可枚举类,应该实现这些泛型接口。非泛型的版本可用于C# 2.0以前没有泛型的遗留代码。
-
-
尽管泛型版本和非泛型版本一样简单易用,但泛型版本结构略显复杂。
![]() 实现IEnumerator |
![]() 实现IEnumerable |
结尾
书籍:C#图解教程
著:【美】丹尼尔 · 索利斯;卡尔 · 施罗坦博尔
译:窦衍森;姚琪琳
ISBN:978-7-115-51918-4
版次:第5版
发行:人民邮电出版社
※敬请购买正版书籍,侵删请联系85863947@qq.com※
※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※