C Sharp(十三)
發佈於 2018-11-19
这一篇,我们看看 C# 中的枚举器和迭代器的基本概念。 之前我们说过可以使用 foreach 来遍历数组元素,本篇来讨论为什么数组可以使用 foreach 语句处理,我们可以还使用迭代器来使得自定义类型也可以使用 foreach。
为什么数组可以使用 foreach 呢?因为数组可以提供一个枚举器(enumerator)对象。枚举器对象可以依次返回数组元素。 获取一个对象的枚举器可以调用对象的 GetEnumerator 方法。实现了 GetEnumerator 方法的对象称为可枚举(enumerable)对象。
foreach 语句就是用来配合可枚举类型一起使用的,他会执行下列行为:
foreach (Type ValName in EnumerableObject) {
//...
}
实现 IEnumerator 接口的枚举器包含三个函数成员:
下面代码与直接使用 foreach 产生的结果是一样的:
using System.Collections;
class Program
{
static void Main(string[] args)
{
int[] MyArr = { 1, 2, 3, 5, 6, 7 };
IEnumerator ie = MyArr.GetEnumerator();
while (ie.MoveNext())
{
int current = (int)ie.Current;
Console.WriteLine(current);
}
}
}
可枚举类型是指实现了 IEnumerable 接口的类。IEnumerable 只有一个函数成员:
using System.Collections;
class MyClass : IEnumerable
{
public IEnumerator GetEnumerator()
{
//...
}
}
using System.Collections;
class ColorEnumerator : IEnumerator
{
private string[] _colors;
private int _position = -1;
public ColorEnumerator(string[] colors)
{
_colors = new string[colors.Length];
for (int i = 0; i < colors.Length; i++) {
_colors[i] = colors[i];
}
}
public object Current {
get {
if (_position <= -1 || _position >= _colors.Length) {
throw new InvalidOperationException();
}
return _colors[_position];
}
}
public bool MoveNext(()
{
if (_position < _colors.Length - 1) {
_position++;
return true;
}
return false;
}
public void Reset()
{
_position = -1;
}
}
class Colors : IEnumerable
{
private string[] _colors;
public Colors(string[] colors)
{
_colors = new string[colors.Length];
for (int i = 0; i < colors.Length; i++) {
_colors[i] = colors[i];
}
}
public IEnumerator GetEnumerator()
{
return new ColorEnumerator(_colors);
}
}
class Progeam
{
static void Main()
{
Colors colors = new Colors(new string[] {"red", "green", "blue", "yellow"});
foreach (string color in colors) {
Console.WriteLine(color);
}
}
}
之前我们写的都是非泛型版本,实际工作中,我们基本都使用泛型版本的 IEnumerator 和 IEnumerable 。非泛型版本只是兼任 2.0 版本之前无泛型的遗留代码。
泛型与非泛型版本的主要区别是:
C# 2.0 之后,提供了更简单的创建枚举器和可枚举类型的方式。这种结构称为迭代器(iterator)。
public IEnumerator<string> BlackAndWhite()
{
yield return "black";
yield return "gray";
yield return "white";
}