C#迭代器原理

转载 2015年11月19日 10:11:46

转载自:http://www.cnblogs.com/eagle1986/archive/2011/12/05/2276293.html

迭代器概述

迭代器是可以返回相同类型的值的有序序列的一段代码。

迭代器可用作方法、运算符或 get 访问器的代码体。

迭代器代码使用 yield return 语句依次返回每个元素。yield break 将终止迭代。有关更多信息,请参见 yield。

可以在类中实现多个迭代器。每个迭代器都必须像任何类成员一样有唯一的名称,并且可以在 foreach 语句中被客户端代码调用,如下所示:foreach(int x in SampleClass.Iterator2){}

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

迭代器是使用在foreach中的集合。在C#2.0中使用迭代器创建一个用于foreach的集合,实现上比较简单:继承于IEumnerable,并实现GetEnumerator()。

首先这个集合要基于IEnumerable(可以使用泛型),下面先来实现一个非泛型版的迭代器。代码如下(非泛型代码示例来源于MSDN):

 

public class DaysOfTheWeek : System.Collections.IEnumerable
   {
     string[] m_Days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
 
     public System.Collections.IEnumerator GetEnumerator()
     {
       for (int i = 0; i < m_Days.Length; i++)
       {
         yield return m_Days[i];
       }
     }
   }
 
   class TestDaysOfTheWeek
   {
     static void Main()
     {
       DaysOfTheWeek week = new DaysOfTheWeek();
       foreach (string day in week)
       {
         System.Console.Write(day + " ");
       }
       Console.Read();
     }
  }

 

操作结果是:

Sun Mon Tue Wed Thr Fri Sat

其中yied return关键字产生枚举元素

泛型版迭代器的实现代码如下:

 

static void Main(string[] args)
    {
 
      Stack<int> stack = new Stack<int>();
      stack.items = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
      foreach (int i in stack)
      {
        Console.WriteLine(i);
      }
      Console.Read();
   }
 
public class Stack<T> : IEnumerable<T>
  {
    public T[] items;
 
    public IEnumerator<T> GetEnumerator()
    {
      for (int i = 0; i < items.Length; i++)
      {
        yield return items[i];
      }
    }
 
    IEnumerator IEnumerable.GetEnumerator()
    {
      return GetEnumerator();
    }
}

 

运行结果如下:

1
2
3
4
5
6
7
8
9
10

其中G在实现泛型迭代器时我一直没有写IEnumerator IEnumerable.GetEnumerator()这个方法,所以编译器一直在给我报错,(猜想)这个方法应该IEnumerator<T>接口中的一个抽象方法。而这个方法中调用的GetEnumerator(),通过集成环境中的提示发现,实际上是上面写到的IEnumerator<T> GetEnumerator()这个泛型方法。

在自定义迭代器时,我们可以利用yield break关键字跳出循环。如上面的例子中,我们想只输出小于等于5的项,调整上面代码,如:

 

public class Stack<T> : IEnumerable<T>
  {
    public T[] items;

    public IEnumerator<T> GetEnumerator()
    {

      for (int i = 0; i < items.Length; i++)
      {        

        if ((Convert.ToInt32(items[i]) > 5))
          yield break;

        yield return items[i];
      }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      return GetEnumerator();
    }
  }

 

 

操作结果:

 

1
2
3
4
5

 

迭代器的机制:

 

  实际上迭代器只是在C#2.0中通过编译器一层额外处理的,用来简化创建可用于foreach的枚举集合的工作,从性能上没有什么变化。对于其生成的中间语言没有太多的变化。

实例:定义和使用命名迭代器

 

   class Class1
  {
    public IEnumerator GetEnumerator()
    {
      for (int i = 0; i < 10; i++)
      {
        yield return i;
      }
    }

 

    // 定义一个命名的迭代器,并可以提供参数
    public IEnumerable MaxToMin(int min, int max)
    {
      for (int i = max; i >= min; i--)
      {
        yield return i;
      }
    }

 

    // 定义一个迭代器类型的属性,
    public IEnumerable MinToMax
    {
      // this表示该类实例,因为该类实现了GetEnumerator(),它是可枚举的
      get { yield return this; }
    }

 

    public IEnumerable GetDescriptions()
    {
      yield return "this is my test";
      yield return "class name is class1";
      yield return "ktgu";
    }
  }

 

  static void Main(string[] args)
  {
    
    Class1 c = new Class1();

 

    foreach (int i in c)
    {
      Console.WriteLine(i);
    }

 

    foreach (int i in c.MaxToMin(1, 10))
    {
      Console.WriteLine(i);
    }

 

    foreach (int i in c.MinToMax)
    {
      Console.WriteLine(i);
    }

 

    foreach (string s in c.GetDescriptions())
    {
      Console.WriteLine(s);
    }
   }

 


迭代效果及实现要点

 

1.迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。

 

2.迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。

 

3.迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。

 

适用性

 

1.访问一个聚合对象的内容而无需暴露它的内部表示。

 

2.支持对聚合对象的多种遍历。

 

3.为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。

 

总结

 

Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据

参考:
C#2.0-迭代器应用 http://cs.alienwave.cn/Topic/1347.aspx
迭代器(C# 编程指南) http://msdn2.microsoft.com/zh-cn/library/dscyy5s0(VS.80).aspx


C#迭代器——由foreach说开去

C#迭代器——由foreach说开去 IEnumerable和IEnmerator yield retun StartCoroutine

C# 枚举数和迭代器总结

1.为什么数组可以使用foreach遍历。原因是数组可以按需提供一个叫做枚举数的对象。枚举数可以依次返回请求的数组元素。 我的话说就是:数组实现了一个叫IEnumerable的接口,该接口有一个方法...

C# 迭代器

例子如下: 一般是在用foreach循环访问自定义结构类时用到这个。遍历是通过IEnumerable.GetEnumerator()来实现的。 class A:IEnumerable ...

[C#基础知识系列]专题十二:迭代器

引言:    在C# 1.0中我们经常使用foreach来遍历一个集合中的元素,然而一个类型要能够使用foreach关键字来对其进行遍历必须实现IEnumerable或IEnumerable接口,(...

C# 2.0 新特性之迭代器, Yield Return

本文摘自:http://www.cnblogs.com/montaque/archive/2005/04/21/142844.htmlC# 2.0 可能讨论比较多的是泛型, 其次可能就是迭代器,匿名方...
  • VS_URL
  • VS_URL
  • 2012年07月23日 15:15
  • 1323

C#关键字之yield(迭代器)

今天讲到迭代器,对迭代器中yield关键字做了研究。   说起yield,不得不先说说迭代器。 迭代器是C# 2.0中的新功能,有了它,我们就可以在自己的类或者结构中支持foreach迭代而不必...
  • wmqdn
  • wmqdn
  • 2012年05月05日 09:50
  • 360

C#迭代器

转载自:http://www.cnblogs.com/kenshincui/archive/2011/04/04/2005297.html 摘要:迭代器是C#2.0中添加的功能,它能够使我们在类或结...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#迭代器原理
举报原因:
原因补充:

(最多只允许输入30个字)