C#基础--迭代器初识
foreach语句是枚举器(enumerator)的消费者,而迭代器(iterator)是枚举器的产生者。
迭代器模式能提供一种顺序访问一个集合内部的元素,而又不会暴露其内部的方法。当然其缺点就是用foreach语句遍历的同时,不能修改集合内部的元素。
我们已经在foreach语句中接触过了它 foreach (var item in collection) ,C#利用foreach实现了访问迭代器的内置支持。
实际上foreach被编译后会产生GetEnumerator和MoveNext方法,还有current属性。
一.C#2 便捷的语法糖
下面我们先来介绍C#2.0为实现迭代器提供的便捷语法。
先看两个单词的翻译 enumerator(枚举器) enumerable(可枚举类型)
下面举个例子:
using System; using System.Collections; using System.Collections.Generic; namespace ConsoleApp1 { class Program { static IEnumerable<string> AddAB(int Count) { string str = "h"; for (int i = 0 ; i < Count; i++) { yield return str; str += "a"; } Console.WriteLine(""); for (int i = 0 ; i < Count; i++) { Console.WriteLine("before yoeld return "+str); yield return str; str += "b"; } } static void Main(string[] args) { foreach (var str in AddAB(3)) { Console.WriteLine(str); } } } }
IEnumerable接口的GetEnumerator方法实现了IEnumerator枚举器类的实例。所以上文的代码是没问题的,后面会给大家示范用IEnumertor接口实现迭代器。
yield return语句的意思是你向我请求从枚举器产生的下一个元素。
每次执行到yield return就会返回到他调用者那,但还会执行yield return之后的语句,直到碰到下一条yield return时停止。这个状态一直持续到foreach语句的结束。
二.C#1 手写迭代器
再来看看这句话:foreach语句是枚举器(enumerator)的消费者,而迭代器(iterator)是枚举器的产生者。
【enumerator(枚举器) enumerable(可枚举类型)】
foreach需要获得一个enumerator,而我们需要用IEnumerator接口实现迭代器。
using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace ConsoleApp1 { class Alp : IEnumerable { string[] value = { "a", "b", "c" }; public IEnumerator GetEnumerator() { return new AlpEnumerator(value); } } class AlpEnumerator : IEnumerator { string[] alp; int position = -1; public AlpEnumerator(string[] str) { alp = new string[str.Length]; for (int i = 0; i < str.Length; i++) { alp[i] = str[i]; } } public object Current { get { if (position == -1) throw new InvalidOperationException(); if (position >= alp.Length) throw new InvalidOperationException(); return alp[position]; } } public bool MoveNext() { if (position < alp.Length - 1) { position++; return true; } else return false; } public void Reset() { position = -1; } } class Program { static void Main(string[] args) { Alp alp = new Alp(); foreach (var item in alp) { Console.WriteLine(item); } } } }
- Current 获取当前位置
- MoveNext 判断是否可移动到下一位
- Reset 将位置重置为初始位置