【c#迭代器】
在.NET中,迭代器模式被IEnumerator和IEnumerable及其对应的泛型接口所封装。如果一个类实现了IEnumerable接口,那么就能够被迭代;调用GetEnumerator方法将返回IEnumerator接口的实现,它就是迭代器本身。迭代器类似数据库中的游标,他是数据序列中的一个位置记录。迭代器只能向前移动,同一数据序列中可以有多个迭代器同时对数据进行操作。
以一个手动迭代器为例子,进行详解迭代器:假如我们有一个集合添加“我,爱,的,是,c#”五个字母,那么输出时想从第三个开始输出,结果既是“是,c#,我,爱,的”,该怎么实现?迭代器就登场了......
/// <summary>
/// 主题:C#扫盲之迭代器
/// 时间:2013-1-4 20:33:50
/// 描述:利用迭代器输出字符串,从自己编写到优化
/// 作者:白宁超
/// </summary>
/// <param name="args"></param>
Sample类的迭代及创建如下:
/// <summary> /// 主题:类的迭代输出初始化字符串 /// 时间:2013-1-4 20:40:15 /// 描述:通过创建Sample,实现字符串从第三个数打印出 /// 作者:白宁超 /// </summary> class Sample:IEnumerable { public Object[] values; //定义对象作为集合参数 public int starting; //定义迭代起始点 public Sample(Object[] values, Int32 starting) //构造方法 { this.values = values; this.starting = starting; } // 摘要:返回一个循环访问集合的枚举器。 // 返回结果:可用于循环访问集合的 System.Collections.IEnumerator 对象。 public IEnumerator GetEnumerator() { return new IterationSample(this); } }
IterationSample迭代如下:为Sample类GetEnumerator方法提供返回值
/// <summary> /// 主题:构造类的返回值 /// 时间:2013-1-4 20:41:49 /// 描述: IterationSample类来实现迭代器本身,通过GetEnumerator方法返回集合值 /// 作者:白宁超 /// </summary> class IterationSample : IEnumerator { Sample parent;//迭代的对象 int position;//当前游标的位置 internal IterationSample(Sample parent) { this.parent = parent; position = -1;// 数组元素下标从0开始,初始时默认当前游标设置为 -1,即在第一个元素之前, } //获取集合中的当前元素 public object Current { get { if (position == -1 || position == parent.values.Length)//第一个之前和最后一个自后的访问非法 { throw new InvalidOperationException(); } int index = position + parent.starting;//考虑自定义开始位置的情况 index = index % parent.values.Length; return parent.values[index]; } } //将枚举数推进到集合的下一个元素 public bool MoveNext() { if (position != parent.values.Length) //判断当前位置是否为最后一个,如果不是游标自增 { position++; } return position < parent.values.Length; } //将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。 public void Reset() { position = -1;//将游标重置为-1 } }
/// <summary> /// 主题:C#扫盲之迭代器 /// 时间:2013-1-4 20:33:50 /// 描述:利用迭代器输出字符串,从自己编写到优化 /// 作者:白宁超 /// </summary> /// <param name="args"></param> static void Main(string[] args) { //简单迭代器操作 object[] values = { "我", "爱", "的", "是", "C#" };//初始化数组“我爱的是C#” Sample collection = new Sample(values, 3); //Sample类实例化 foreach (object x in collection) //循环打印 { Console.WriteLine(x); } Console.ReadKey(); }
以上是手写迭代器,还有一个更简便的方法,可以省去IterationSample类的迭代,即只需要Sample类GetEnumerator方法添加for循环语句,利用yield ruturn便可得到我们所希望的结果:
// 摘要:返回一个循环访问集合的枚举器。 // 返回结果:可用于循环访问集合的 System.Collections.IEnumerator 对象。 public IEnumerator GetEnumerator() { //return new IterationSample(this); //此方法减少代码量,是代码更优雅 for (int index = 0; index < this.values.Length; index++) { yield return values[(index + starting) % values.Length]; } }
IEnumerable<T>在LINQ中最重要的一个接口,如果想要在LINQ To Object上实现自己的LINQ操作,就会觉得迭代的方便性。值得注意的是,yield return语句停止了方法的执行,而不是退出方法,要想退出需要yield break,这根普通方法中的return一样。
作者:白宁超,工学硕士,现工作于四川省计算机研究院,研究方向是自然语言处理和机器学习。曾参与国家自然基金项目和四川省科技支撑计划等多个省级项目。著有《自然语言处理理论与实战》一书。 自然语言处理与机器学习技术交流群号:436303759 。
出处:http://www.cnblogs.com/baiboy/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。