C#-14 枚举器和迭代器

  • C#-14 枚举器和迭代器已关闭评论
  • 252 次浏览
  • A+
所属分类:.NET技术
摘要

当我们为数组使用foreach语句时,这个语句为我们依次取出了数组中的每一个元素。


一 枚举器和可枚举类型

当我们为数组使用foreach语句时,这个语句为我们依次取出了数组中的每一个元素。

var arrInt = new int[] { 11, 12, 13, 14 }; foreach (var item in arrInt) {     Console.WriteLine(item); }

原因是数组实现了IEnumerable接口,接口提供了一个GetEnumerator方法可以获取一个实现了IEnumerator接口的枚举器对象。

枚举器可以依次返回请求的数组中的元素。

实现了IEnumerable接口类型叫做可枚举类型。数组是可枚举类型。

public interface IEnumerable {     // 摘要: 返回循环访问集合的枚举器。     // 返回结果:一个可用于循环访问集合的 System.Collections.IEnumerator 对象。     IEnumerator GetEnumerator(); }

 

foreach语句设计用来和可枚举类型一起使用。只要给它的遍历对象是可枚举类型,它就会执行如下行为:

  • 通过调用GetEnumerator方法获取对象的枚举器;
  • 从枚举器中请求每一项并把它作为迭代变量。

二 IEnumerator接口

IEnumerator接口的定义如下:

public interface IEnumerator {     // 摘要:获取集合中位于枚举数当前位置的元素     // 返回结果:集合中位于枚举数当前位置的元素。     object Current { get; }
// 摘要:将枚举数推进到集合的下一个元素。 // 返回结果:如果枚举数已成功地推进到下一个元素,则为 true;如果枚举数传递到集合的末尾,则为 false。 // 异常:T:System.InvalidOperationException:创建枚举器后,已修改该集合。 bool MoveNext(); // 摘要:将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。 // 异常: T:System.InvalidOperationException: 创建枚举器后,已修改该集合。 void Reset(); }

有了枚举器,就可以使用MoveNext和Current来模仿foreach循环:

int[] arrInt = new int[] { 11, 12, 13, 14 }; foreach (var item in arrInt) {     Console.WriteLine(item); }  var enumerator = arrInt.GetEnumerator(); while (enumerator.MoveNext()) {     var item = (int)enumerator.Current;     Console.WriteLine(item); }

下面是一个使用IEnumerator和IEnumerable的小例子:

C#-14 枚举器和迭代器C#-14 枚举器和迭代器

class Program {     static void Main(string[] args)     {         var myColor = new MyColors();         foreach (var item in myColor)         {             Console.WriteLine(item);         }     } }  class ColorEnumeraotr : IEnumerator {     string[] _colors;     int _position = -1;      public ColorEnumeraotr(string[] theColors)     {         _colors = new string[theColors.Length];         for (int i = 0; i < theColors.Length; i++)         {             _colors[i] = theColors[i];         }     }          public object Current     {         get         {             if (_position == -1)                 throw new InvalidOperationException();             if (_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 MyColors : IEnumerable  {     string[] Colors = new string[] { "red","blue","yellow","green","white"};      public IEnumerator GetEnumerator()     {         return new ColorEnumeraotr(Colors);     } }

View Code

三 泛型枚举接口

非泛型接口的实现不是类型安全的,它返回object的引用,然后必须转化为实际类型。

所以实际上,在多数情况下,我们应该使用泛型版本的IEnumerable<T>和IEnumerator<T>。

泛型接口的枚举器是类型安全的,它返回实际类型的引用。

IEnumerable<T>接口的GetEnumerator方法返回实现IEnumerator<T>的枚举器对象。

实现IEnumerator<T>的枚举器类的Current属性,它返回T类型的对象。

 

四 迭代器

C#从2.0版本开始提供了更简单的创建枚举器和可枚举类型的方式。这种结构叫做迭代器。

迭代器块是有一个或多个yield语句的代码块。

迭代器块与其他代码块不同。其他块包含的语句是命令式的,也就是块中的语句依次执行,最后离开块。

而迭代器块是描述了希望编译器为我们创建的枚举器类的行为,迭代器块中的代码描述了如何枚举元素。

迭代器块有两个特殊语句:

  • yield return : 指定了序列中返回的下一项;
  • yield break : 指定在序列中没有其他项。
//产生枚举器的迭代器 public IEnumerator<string> IteratorMethod1()  {     yield return "red";     yield return "blue";     yield return "yellow"; }  //产生可枚举类型的迭代器 public IEnumerable<string> IteratorMethod2() {     yield return "red";     yield return "blue";     yield return "yellow"; }

4.1 使用迭代器来创建枚举器

下面代码演示如何使用迭代器来创建枚举器:

C#-14 枚举器和迭代器C#-14 枚举器和迭代器

class Program {     static void Main(string[] args)     {         var mc = new MyClass();         foreach (var item in mc)         {             Console.WriteLine(item);         }     } }  class MyClass  {     public IEnumerator<string> GetEnumerator()     {         return MyEnumerator();  //返回枚举器     }      //迭代器     public IEnumerator<string> MyEnumerator()      {         yield return "red";         yield return "blue";         yield return "yellow";     } }

View Code

4.2 使用迭代器来创建可枚举类型

下面代码演示如何使用迭代器来创建可枚举类型:

C#-14 枚举器和迭代器C#-14 枚举器和迭代器

class Program {     static void Main(string[] args)     {         var mc = new MyClass();         foreach (var item in mc)         {             Console.WriteLine(item);         }          foreach (var item in mc.MyEnumerable())         {             Console.WriteLine(item);         }     } }  class MyClass  {     public IEnumerator<string> GetEnumerator()     {         IEnumerable<string> myEnumerable = MyEnumerable();         return myEnumerable.GetEnumerator();     }          public IEnumerable<string> MyEnumerable()      {         yield return "red";         yield return "blue";         yield return "yellow";     } }

View Code