总目录
C# 语法总目录
枚举器和迭代器
- 枚举器和迭代器
- 1. 枚举器
- 2. 可枚举对象
- 3. 迭代器
- 4. 迭代器语义
- 5. yield break 语句
- 6. 组合序列
枚举器和迭代器
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# 语法总目录