现在的位置: 首页 > 综合 > 正文

C#学习笔记—迭代器

2012年02月29日 ⁄ 综合 ⁄ 共 2906字 ⁄ 字号 评论关闭
foreach隐式调用无参的GetEnumerator 方法来获取一个enumerator,但是一个集合只能有一个无参的GetEnumerator 方法,通常有这样的需求,根据参数的不同实现不同的枚举顺序或者枚举方式.在这些情形下,可以利用iterator来实现返回enumerable interfaces的属性和方法.比如Stack<T>实现了IEnumerable<T>类型的TopToBottomBottomToTop

using System.Collections.Generic;

public class Stack<T>: IEnumerable<T>


{

    T[] items;

    
int
 count;

    
public void Push(T data) {}


    
public T Pop() {}

    
public IEnumerator<T> GetEnumerator() {

        
for (int i = count – 1; i >= 0--i) 
{

           yield 
return
 items[i];

        }


    }


    
public IEnumerable<T> TopToBottom {

        
get 
{

           
return this
;

        }


    }


    
public IEnumerable<T> BottomToTop {

        
get 
{

            
for (int i = 0; i < count; i++
{

                    yield 
return
 items[i];

            }


        }


    }


}

TopToBottom 属性简单的返回this,因为statck本身就是enumerable,BottomToTop 用iterator返回了一个enumerable ,下面的例子展示如何使用这些属性来枚举栈中的成员.

using System;

class Test

{

    
static void Main() {

        Stack
<int> stack = new Stack<int>();

        
for (int i = 0; i < 10; i++) stack.Push(i);

        
foreach (int i in stack.TopToBottom) Console.Write("{0} ", i);

        Console.WriteLine();

        
foreach (int i in stack.BottomToTop) Console.Write("{0} ", i);

        Console.WriteLine();

    }


}


当然这些属性也可以用在出foreach语句之外的地方,下面的例子展示了通过单独的Print 方法调用属性的结果.这个例子也展示了用iterator实现的含参的FromToBy 方法.

using System;

using System.Collections.Generic;

class Test

{

    
static void Print(IEnumerable<int> collection) {

        
foreach (int i in collection) Console.Write("{0} ", i);

        Console.WriteLine();

    }


    
static IEnumerable<int> FromToBy(int from, int to, int by) {

        
for (int i = from; i <= to; i += by) {

            yield 
return i;

        }


    }


    
static void Main() {

        Stack
<int> stack = new Stack<int>();

        
for (int i = 0; i < 10; i++) stack.Push(i);

        Print(stack.TopToBottom);

        Print(stack.BottomToTop);

        Print(FromToBy(
10202));

    }


}

范型或者非范型的enumerable interfaces 接口都包含唯一的成员无参和返回类型为enumerable interface的GetEnumerator 方法,一个enumerable 做为一个enumerator 工厂(factory),欠当地实现enumerables 保证每次调用GetEnumerator 方法时产生独立的enumerators,如果enumerable 内部的状态在两次调用GetEnumerator没有改变,两次返回的enumerators 应该是顺序相同的同一个数据集.这个必须得到保证即使enumerators的声明周期交迭.

using System;

using System.Collections.Generic;

class Test

{

    
static IEnumerable<int> FromTo(int from, int to) {

        
while (from <= to) yield return from++;

    }


    
static void Main() {

        IEnumerable
<int> e = FromTo(110);

        
foreach (int x in e) {

            
foreach (int y in e) {

                Console.Write(
"{0,3} ", x * y);

            }


            Console.WriteLine();

        }


    }


}

上面的代码实现了简单的从1到10的乘法表,注意方法FromTo只被调用了一次来获取enumerable  e,但是e.GetEnumerator()方法调用了多次(通过foreach表达式)来产生多个相同的enumerators,这些enumerators 都封装了FromTo方法中指定的iterator代码,注意迭代器代码修改From的值.但是这些enumerators表现为各自独立,因为每个enumerator有自己的From和To参数的拷贝.enumerators 之间的短暂状态的共享是在实现enumerables 和enumerators的时候应该避免的比较容易违反的隐含缺陷,C# iterator被设计用来避免这些问题,从而用简单和直观的方式实现健壮的enumerables 和enumerators.

抱歉!评论已关闭.