实现迭代器的捷径
2016-01-29 15:45
211 查看
迭代器模式是行为模式的一种范例,行为模式是一种简化对象之间通信的设计模式。它允许你访问一个数据序列中的所有元素,而无须关心序列是什么类型。它能有效的构建一个数据管道,经过一系列不同的转换或过滤后再从管道的另一端出来。(也是LINQ核心模式之一)
迭代模式是通过IEnumerator和IEnumerable接口及它们的泛型等价物来封装的。
foreach语句被编译后会调用GetEnumerator和MoveNext方法以及Current属性,如果实现IDisposable,程序还是自动销毁迭代对象。
C#1:手写迭代器痛苦
迭代模式不用一次返回所有数据——调用代码一次只需获取一个元素。
C#2:利用yield语句简化迭代器
迭代器工作流程
return作用:
一:给调用者提供返回值
二:退出时执行合适的finally代码块
使用yieldbreak结束迭代器的执行,finally代码块的执行
具体实现中的奇特之处
第一次调用MoveNext之前,Current属性总是返回迭代器产生类型的默认值
在MoveNext返回false之后,Current属性总是返回最后的生成值
迭代模式是通过IEnumerator和IEnumerable接口及它们的泛型等价物来封装的。
foreach语句被编译后会调用GetEnumerator和MoveNext方法以及Current属性,如果实现IDisposable,程序还是自动销毁迭代对象。
C#1:手写迭代器痛苦
迭代模式不用一次返回所有数据——调用代码一次只需获取一个元素。
#region6-1使用新集合类型代码
object[]values={"a","b","c","d","e"};
IterationSamplecollection=newIterationSample(values,3);
foreach(objectxincollection)
{
Console.WriteLine(x);
}
#endregion
#region新集合类型框架,不包含迭代器的实现
publicclassIterationSample:IEnumerable
{
publicobject[]values;
publicintstartingPoint;
publicIterationSample(object[]values,intstartingPoint)
{
this.values=values;
this.startingPoint=startingPoint;
}
publicIEnumeratorGetEnumerator()
{
returnnewIterationSampleIterator(this);
}
}
#endregion
#region6-3嵌套类实现集合迭代器
classIterationSampleIterator:IEnumerator
{
IterationSampleparent;//正在迭代的集合
intposition;
internalIterationSampleIterator(IterationSampleparent)
{
this.parent=parent;
position=-1;
}
publicboolMoveNext()//将枚举数推进到集合的下一个元素。
{
if(position!=parent.values.Length)//遍历,增加position值
{
position++;
}
returnposition<parent.values.Length;
}
publicobjectCurrent//获取集合中的当前元素。先调用MoveNext方法
{
get
{
if(position==-1||position==parent.values.Length)//防止访问第一个元素之前和最后一个元素之后
{
thrownewInvalidOperationException();
}
intindex=position+parent.startingPoint;
index=index%parent.values.Length;//获取当前索引下标
returnparent.values[index];
}
}
publicvoidReset()
{
position=-1;
}
}
#endregion
C#2:利用yield语句简化迭代器
#region6-4利用C#2和yieidreturn来迭代实例
publicIEnumeratorGetEnumerator()
{
for(intindex=0;index<values.Length;index++)
{
yieldreturnvalues[(index+startingPoint)%values.Length];//实现迭代器的方法
}
}
#endregion
迭代器工作流程
#region6-5
staticreadonlystringPadding=newstring('',30);
staticIEnumerable<int>CreateEnumerable()
{
Console.WriteLine("{0}StartofCreateEnumerable()",Padding);
for(inti=0;i<3;i++)
{
Console.WriteLine("{0}Abouttoyield{1}",Padding,i);
yieldreturni;//代码停止执行,下次调用MoveNext时继续调用
Console.WriteLine("{0}Afteryield",Padding);
}
Console.WriteLine("{0}Yieldingfinalvalue",Padding);
yieldreturn-1;
Console.WriteLine("{0}EndofCreateEnumerable()",Padding);//返回false结束方法执行
}
#endregion
#region6-5显示迭代器及其调用者之间的调用序列
IEnumerable<int>iterable=CreateEnumerable();
IEnumerator<int>iterator=iterable.GetEnumerator();
Console.WriteLine("stringtoiterate");
//while(true)
//{
//Console.WriteLine("CallingMoveNext()...");
//boolresult=iterator.MoveNext();
//Console.WriteLine("...MoveNextresult={0}",iterator.Current);
//}
for(inti=0;i<7;i++)
{
Console.WriteLine("CallingMoveNext()...");
boolresult=iterator.MoveNext();
Console.WriteLine("...MoveNextresult={0}",result);
}
#endregion
return作用:
一:给调用者提供返回值
二:退出时执行合适的finally代码块
使用yieldbreak结束迭代器的执行,finally代码块的执行
#region6-6演示yieldbreak语句
DateTimestop=DateTime.Now.AddSeconds(1);//停止时间
Stopwatchstopwatch=newStopwatch();
stopwatch.Start();//测试时间
foreach(intiinCountWithTimeLimit(stop))
{
Console.WriteLine("Received{0}",i);
Thread.Sleep(10);//执行一次,间隔时间
}
stopwatch.Stop();
doublemm=stopwatch.ElapsedMilliseconds;
Console.WriteLine(mm);
#endregion
#region6-6
staticIEnumerable<int>CountWithTimeLimit(DateTimelimit)
{
try
{
for(inti=1;i<=100;i++)
{
if(DateTime.Now>=limit)
{
yieldbreak;//时间到了,停止运行
}
yieldreturni;//暂时停止方法,并没有退出方法
}
}
finally
{
Console.WriteLine("Stooping");
}
}
#endregion
具体实现中的奇特之处
第一次调用MoveNext之前,Current属性总是返回迭代器产生类型的默认值
在MoveNext返回false之后,Current属性总是返回最后的生成值
相关文章推荐
- iOS:基于Socket的第三方框架CocoaAsyncSocket的使用
- cisco sdm登录 SSH配置学习笔记
- web性能优化(项目的规范&优化)
- 简单总结修改项目中navBar和tabBar的坑
- 冒泡排序
- 胶水
- 进入快速委托通道
- 分享最近写的 两条sql语句
- java引用的问题
- 编写 Vim 脚本
- Json数据格式和XML数据格式的分析
- 详解C#中的属性和属性的使用
- 选择排序
- 精通JS正则表达式(推荐)
- 可空类型
- smartSVN unable to connect to a respository at url
- 【复习笔记】贝叶斯学习
- 删除.java文件中所有未用到的引用的包的菜单命令或快捷键是什么?
- 前端与SEO ①:结构、表现、行为分离
- linux串口类