C# 迭代器(1)

节选自《.NET平台与C#面向对象程序设计》迭代器部分

要扎扎实实看书做笔记理解,不然写程序要用到的时候概念很模糊,不会用。

迭代器是C#2.0中的新功能,它是方法、get访问器或运算符。使得能够在类或结构中支持foreach迭代,而不必实现整个IEnumerable接口,只需提供一个迭代器即可遍历类中的数据结构。当编译器检测到迭代器时,将自动生成IEnumerable或IEnumerable接口的Current、MoveNext和Dispose方法。

  1. 概述

    迭代器是可以返回相同数据类型的值的有序序列的一段代码,科可用做方法、运算符或get访问器的代码体。

    迭代器代码使用yield return语句一次返回每一个元素,yield break将终止迭代。

    可以在类中实现多个迭代器,每个迭代器都必须与任何类成员一样有唯一名称并且可以在foreach语句中呗客户端代码调用,如:

    foreach(int x in SampleClass.Iterator2){}

    迭代器的返回类型必须为IEnumerable、IEnumerator、IEnumerable或IEnumerator。

    yield关键字用于指定返回的值,到达yield return语句时会保存当前位置,下次调用迭代器时将从此位置重新开始执行。

    迭代器对集合类特别有用,它提供一种简单的方法来迭代不常用的数据结构,如二进制树。

  2. 使用
    创建迭代器最常用的方法是为IEnumerable接口实现GetEnumerator方法,如:
       1:  public System.Collections.IEnumerator GetEnumerator()
       2:  {
       3:      for(int i=0;i<max;i++)
       4:      {
       5:          yield return i;
       6:      }
       7:  }
    GetEunmerator方法的存在使得类型成为可枚举的类型,并允许使用foreach语句。如果上面的方法是ListClass的类定义的一部分,则可以对该类使用foreach,如:

    static void Main()
    {
        foreach(int i
        ListClass listClass1=new ListClass();
     in listClass1)
        {
            System.Console.WriteLine(i);
        }
    }
    foreach语句调用ListClass.GetEnumerator()并使用返回的枚举数来循环访问值。
    还可以使用命名的迭代器支持通过不同的方式循环访问同一数据集合,如可以提供一个按升序和降序返回元素的迭代器。迭代器可以带有参数,以允许客户端控制全部或部分迭代行为。下面的迭代器使用命名的迭代器SampleIterator实现IEnumerable接口:
    //Implementing the enumerable pattern
    public System.Collections.IEnumerable SampleIterator(int start,int end)
    {
        for(int i=start;i<=end;i++)
        {
            yield return i;
        }
    }

    命名的迭代器的调用方法如下:
    ListClass test=new ListClass();
    foreach(int n in test.SampleIterator(1,10))
    {
        System.Console.WriteLine(n);
    }

    可以在同一个迭代器中使用多个yield语句,如:
    public System.Collections.IEnumerator GetEunmerator()
    {
        yield return "With an iterator";
        yield return "more than one";
        yield return "value can be returned";
        yield return ".";
    }

    然后可以使用下面的foreach语句输出结果:
    foreach(string element in new TestClass())
    {
        System.Console.Write(element);
    }

    显示:
    With an iterator more than one value can be returned.

    在foreach语句循环的每次后迭代(或对IEnumerator.MoveNext的直接调用)中下一个迭代器代码体将从前一个yield语句之后开始,并继续下一个语句,直至到达迭代器体的结尾或遇到yield break语句。
  3. yield语句
    yield语句在迭代器块中用于为枚举数对象提供值或发出迭代结束信号,其形式如下:
    yield return expression;
    yield break;

    expression参数计算并以枚举数对象值的形式返回,它必须可以隐式转换为迭代器的yield类型。
    yield语句只能出现在iterator块中,该块可用作方法、运算符或访问器的体,这类体受以下约束的控制:
    1、不允许不安全块
    2、参数不能是ref或out
    3、当和expression一起使用时,yield return语句不能出现在catch语句块中或含有一个或多个catch子句的try块中
    如下迭代器块(Power(int number,int power)方法)使用了yield语句,当调用Power方法时,返回一个包含数字幂的可枚举对象。注意该方法的返回类型是IEnumerable(一种迭代器接口类型)
       1:  //yield-example.cs
       2:  using System;
       3:  using System.Collections;
       4:  public class List
       5:  {
       6:      public static IEnumerable Power(int number,int exponeng)
       7:      {
       8:          int counter=0;
       9:          int result=1;
      10:          while(counter++<exponent)
      11:          {
      12:              result=result*number;
      13:              yield return result;
      14:          }
      15:      }
      16:      static void Main()
      17:      {
      18:          foreach(int i in Power(2,8))
      19:          {
      20:              Console.Write("{0}",i);
      21:          }
      22:      }
      23:  }

    输出如下:
    2 4 8 16 32 64 128 256

  4. 迭代程序

    在city集合中使用C#迭代程序:
    public class CityCollection:IEnumerable<string>
    {
        string[] m_Cities=new {"New York","Paris","London"};
        public IEnumerator<string> GetEnumerator()
        {
            for(int i=0;i<m_Cities.Length;i++)
                yield return m_Cities[i];
            }
        }
    }
    非一般集合中使用C#迭代程序:
    public class CityCollection:IEnumerable
    {
        string[] m_Cities=new {"New York","Paris","London"};
        public IEnumerator GetEnumerator()
        {
            for(int i=0;i<m_Cities.Length;i++)
                yield return m_Cities[i];
            }
        }
    }

    此外还可以在完全一般的集合中使用C#迭代程序,使用一般集合和迭代程序时编译器从声明集合所用的类型中知道foreach循环内IEnumerable<ItemType>所用的特定类型

还是不得其解,再看看书

posted @ 2011-06-25 11:45  L Cooper  阅读(401)  评论(0编辑  收藏  举报