C#语言进阶(四) 枚举器和迭代器

总目录
C# 语法总目录

枚举器和迭代器

1. 枚举器

枚举器(Enumerator)是一个只读的且只能在值序列上前移的游标。

任何具有MoveNext方法和Current属性的对象都被称作枚举器。

枚举器实现了下面的接口之一:

  • System.Collections.IEnumerator

  • System.Collections.Generic.IEnumerator

2. 可枚举对象

可枚举对象(Enumerable),它可以生成枚举器。

可枚举的对象可以是:

  • IEnumerable 或 IEnumerable的实现。

  • 具有名为GetEnumerator 的方法并且返回值是一个枚举器 (Enumerator)对象

注意:IEnumerator 和 IEnumerable 定义在 System.Collections 里。

​ IEnumerator 和 IEnumerable 定义在 System.Collections.Generic 里。

//枚举器模板
class Enumerator
{
    public IteratorVariableType Current{ get{...}}
    public bool MoveNext(){...}
}
//可枚举类型模版
class Enumerable
{
    public Enumerator GetEnumerator(){...}
}

3. 迭代器

迭代器是枚举器的生产者。foreach语句是枚举器的消费者。

案例:使用迭代器来返回斐波那契数列(每个数字是前两个数字之和)

using System;
using System.Collections.Generic;
class Test
{
    static void Main()
    {
        foreach(int fib in Fibs(6))
            Console.Write(fib+" ");
    }
    //迭代器方法
    static IEnumerable<int> Fibs(int fibCount)
    {
        for(int i =0,prevFib =1,curFib=1;i<fibCount;i++)
        {
            yield return prevFib;
            int newFib = prevFib+curFib;
            prevFib = curFib;
            curFib = newFib;
        }
    }
}

//输出
1 1 2 3 5 8

4. 迭代器语义

迭代器是包含一个或者多个 yield 语句的方法,属性或者索引器。

//迭代器必须返回以下四个接口之一(否则编译器会产生相应错误):
//可枚举接口
System.Collections.IEnumerable
System.Collections.Generic.IEnumerable<T>

//枚举器接口
System.Collections.IEnumerator
System.Collections.Generic.IEnumerator<T>
    
    
    
//多个yield语句
class Test
{
    static void Main()
    {
        foreach(string s in Foo())
            Console.WriteLine(s);	//输出 One,Two,Three
    }
    static IEnumerable<string> Foo()
    {
        yield return "One";
        yield return "Two";
        yield return "Three";
    }
}

5. yield break 语句

yield break 语句表明迭代器块不再返回更多的元素,而是提前退出。

static IEnumerable<string> Foo(bool breakEarly)
{
    yield return "One";
    yield return "Two";
    if(breakEarly)
        yield break;			//到这里就退出了
    yield return "Three";
}

注意:yield return 语句不能出现在 try…catch…finally 块中,只能出现在try…finally中try块里面。

通常使用foreach或隐式销毁枚举器,但是如果显示使用枚举器,提前结束枚举而不销毁枚举器,绕过了finally块的执行。那么我们可以将枚举器显式包裹在using语句中来避免上述错误。

string firstElement = null;
var sequence = Foo();
using(var enumerator = sequence.GetEnumerator())	//使用using,会自动关闭一个持续流
    if(enumerator.MoveNext())
        firstElement = enumerator.Current;

6. 组合序列

迭代器有高度可组合性。迭代器模式的组合对LINQ非常重要。

class Program
{
    static void Main(string[] args)
    {
        foreach (int fib in EvenNumbersOnly(Fibs(6)))
        {
            Console.WriteLine(fib);
        }
    }
    static IEnumerable<int> Fibs(int fibCount)
    {
        for (int i = 0,prevFib = 1,curFib =1;  i<fibCount; i++)
        {
            yield return prevFib;
            int newFib = prevFib + curFib;
            prevFib = curFib;
            curFib = newFib;
        }
    }

    static IEnumerable<int> EvenNumbersOnly(IEnumerable<int> sequence)
    {
        foreach (int x in sequence)
        {
            if ((x % 2) ==0)
            {
                yield return x;
            }
        }
    }
}

总目录
C# 语法总目录

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值