迭代器模式是设计模式的一种,因为其运用的普遍性,很多语言都有内嵌的原生支持

在.NET中,迭代器模式是通过IEnumerator、IEnumerable两个接口(有非泛型和泛型2种版本)来封装的

迭代器模式的一个重要方面是:不是一次返回所有数据,而是每次调用只返回一个元素

Array、IEnumerable和IEnumerator之间关系如下:

foreach遍历

① Array、集合容器类派生于IEnumerable接口类(该类中含有一个IEnumerator GetEnumerator()接口函数),Array、集合容器类实现了该函数,这使得foreach可对其进行遍历

注:不需要从IEnumerable派生,只要类实现了IEnumerator GetEnumerator()函数,就可以使用foreach遍历该类中的元素

② IEnumerator定义了Current属性来返回游标所在的元素,MoveNext方法移动到下一个元素(若有元素则返回true,若到达末尾则返回false),Reset方法是将游标重置到第一项的位置

int[] IntArray = new int[] { , ,  };

foreach (int n in IntArray)
{
Console.WriteLine(n);
} // 上面的foreach等价于下方的代码实现
IEnumerator e = IntArray.GetEnumerator();
try
{
while (e.MoveNext())
{
Console.WriteLine((int)e.Current);
}
}
finally
{
var disposable = e as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}

在C#1.0中,创建IEnumerator枚举器需要写大量的代码。C#2.0添加了yield语句,让编译器自动创建IEnumerator枚举器。

yield return语句返回集合的一个元素,并移动到下一个元素上。yield break可停止迭代。

非泛型版本IEnumerator

class EnumeratorTest
{
public IEnumerator GetEnumerator()
{
yield return ;
yield return "Good";
}
} EnumeratorTest eTest = new EnumeratorTest();
foreach (object o in eTest)
{
Console.WriteLine(o);
}

编译后生成的代码如下:

class EnumeratorTest
{
public IEnumerator GetEnumerator()
{
return new GenerateEnumerator();
} private sealed class GenerateEnumerator : IEnumerator<object>, IEnumerator, IDisposable
{
// Fields
private int state;
private object current; // Methods
public GenerateEnumerator(int state)
{
this.state = state;
} bool IEnumerator.MoveNext()
{
switch (this.state)
{
case :
this.state = -;
this.current = ;
this.state = ;
return true; case :
this.state = -;
this.current = "Good";
this.state = ;
return true; case :
this.state = -;
break;
}
return false;
} void IEnumerator.Reset()
{
throw new NotSupportedException();
} void IDisposable.Dispose()
{
} // Properties
object IEnumerator<object>.Current
{
get
{
return this.current;
}
}
object IEnumerator.Current
{
get
{
return this.current;
}
}
}
} EnumeratorTest eTest = new EnumeratorTest();
IEnumerator e = eTest.GetEnumerator();
try
{
while (e.MoveNext())
{
Console.WriteLine(e.Current);
}
}
finally
{
var disposable = e as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}

泛型版本IEnumerator<T>

class EnumeratorTest2
{
private bool m_bBreak; public EnumeratorTest2(bool bBreak)
{
m_bBreak = bBreak;
} public IEnumerator<string> GetEnumerator()
{
yield return "Hello";
if (m_bBreak)
{
yield break;
}
yield return "World";
}
} EnumeratorTest2 eTest2 = new EnumeratorTest2(true);
IEnumerator<string> e2 = eTest2.GetEnumerator();
while (e2.MoveNext())
{
Console.WriteLine(e2.Current);
}

编译后生成的代码如下:

class EnumeratorTest2
{
private bool m_bBreak; public EnumeratorTest2(bool bBreak)
{
m_bBreak = bBreak;
} public IEnumerator<string> GetEnumerator()
{
GenerateEnumerator2 e2 = new GenerateEnumerator2();
e2.eTest2 = this;
return e2;
} private sealed class GenerateEnumerator2 : IEnumerator<string>, IEnumerator, IDisposable
{
// Fields
private int state;
private string current; public EnumeratorTest2 eTest2; // Methods
public GenerateEnumerator2(int state)
{
this.state = state;
} bool IEnumerator.MoveNext()
{
switch (this.state)
{
case :
this.state = -;
this.current = "Hello";
this.state = ;
return true; case :
this.state = -;
if (eTest2.m_bBreak)
{
break;
}
this.current = "World";
this.state = ;
return true; case :
this.state = -;
break;
}
return false;
} void IEnumerator.Reset()
{
throw new NotSupportedException();
} void IDisposable.Dispose()
{
} // Properties
string IEnumerator<string>.Current
{
get
{
return this.current;
}
}
object IEnumerator.Current
{
get
{
return this.current;
}
}
}
} EnumeratorTest2 eTest2 = new EnumeratorTest2(true);
IEnumerator<string> e2 = eTest2.GetEnumerator();
while (e2.MoveNext())
{
Console.WriteLine(e2.Current);
}

非泛型版本IEnumerable

class EnumeratorTest3
{
public IEnumerable Test1()
{
yield return ;
yield return ;
}
} EnumeratorTest3 eTest3 = new EnumeratorTest3();
foreach (object o in eTest3.Test1())
{
Console.WriteLine(o);
}

编译后生成的代码如下:

class EnumeratorTest3
{
public IEnumerable Test1()
{
return new GenerateEnumerable3();
} private sealed class GenerateEnumerable3 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
{
// Fields
private int state;
private int current; // Methods
public GenerateEnumerable3(int state)
{
this.state = state;
} bool IEnumerator.MoveNext()
{
switch (this.state)
{
case :
this.state = -;
this.current = ;
this.state = ;
return true; case :
this.state = -;
this.current = ;
this.state = ;
return true; case :
this.state = -;
break;
}
return false;
} IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
return this;
} IEnumerator IEnumerable.GetEnumerator()
{
return this;
} void IEnumerator.Reset()
{
throw new NotSupportedException();
} void IDisposable.Dispose()
{
} // Properties
object IEnumerator<object>.Current
{
get
{
return this.current;
}
}
object IEnumerator.Current
{
get
{
return this.current;
}
}
}
} EnumeratorTest3 eTest3 = new EnumeratorTest3();
IEnumerator e3 = eTest3.Test1().GetEnumerator();
while (e3.MoveNext())
{
Console.WriteLine(e3.Current);
}

泛型版本IEnumerable<T>

class EnumeratorTest4
{
private bool m_bBreak; public EnumeratorTest4(bool bBreak)
{
m_bBreak = bBreak;
} public IEnumerable<float> Test1()
{
yield return 1.0f;
if (m_bBreak)
{
yield break;
}
yield return 3.0f;
}
} EnumeratorTest4 eTest4 = new EnumeratorTest4(true);
foreach (object o in eTest4.Test1())
{
Console.WriteLine(o);
}

编译后生成的代码如下:

class EnumeratorTest4
{
private bool m_bBreak; public EnumeratorTest4(bool bBreak)
{
m_bBreak = bBreak;
} public IEnumerable<float> Test1()
{
GenerateEnumerable4 e4 = new GenerateEnumerable4();
e4.eTest4 = this;
return e4;
} private sealed class GenerateEnumerable4 : IEnumerable<float>, IEnumerable, IEnumerator<float>, IEnumerator, IDisposable
{
// Fields
private int state;
private float current; public EnumeratorTest4 eTest4; // Methods
public GenerateEnumerable4(int state)
{
this.state = state;
} bool IEnumerator.MoveNext()
{
switch (this.state)
{
case :
this.state = -;
this.current = 1.0f;
this.state = ;
return true; case :
this.state = -;
if (this.eTest4.m_bBreak)
{
break;
}
this.current = 3.0f;
this.state = ;
return true; case :
this.state = -;
break;
}
return false;
} IEnumerator<float> IEnumerable<float>.GetEnumerator()
{
return this;
} IEnumerator IEnumerable.GetEnumerator()
{
return this;
} void IEnumerator.Reset()
{
throw new NotSupportedException();
} void IDisposable.Dispose()
{
} // Properties
float IEnumerator<float>.Current
{
get
{
return this.current;
}
}
object IEnumerator.Current
{
get
{
return this.current;
}
}
}
} EnumeratorTest4 eTest4 = new EnumeratorTest4(true);
IEnumerator<float> e4 = eTest4.Test1().GetEnumerator();
while (e4.MoveNext())
{
Console.WriteLine(e4.Current);
}

C# 迭代器与yield关键字的更多相关文章

  1. yield 关键字和迭代器

    一般使用方法     yield 关键字向编译器指示它所在的方法是迭代器块 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值. 这是一个返回值,例如,在 forea ...

  2. Python:容器、迭代对象、迭代器、生成器及yield关键字

            在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(generator).列表/集合/字典推导式(list, ...

  3. C#使用yield关键字构建迭代器

    http://www.cnblogs.com/Huaran1chendu/p/4838536.html 以前,如果我们希望构建支持foreach枚举的自定义集合,只能实现IEnumerable接口(可 ...

  4. 使用yield关键字让自定义集合实现foreach遍历

    一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...

  5. (转) Python Generators(生成器)——yield关键字

    http://blog.csdn.net/scelong/article/details/6969276 生成器是这样一个函数,它记住上一次返回时在函数体中的位置.对生成器函数的第二次(或第 n 次) ...

  6. 转载yield关键字理解

    实现IEnumerable接口及理解yield关键字   [摘要]本文介绍实现IEnumerable接口及理解yield关键字,并讨论IEnumerable接口如何使得foreach语句可以使用. 本 ...

  7. C# 基础小知识之yield 关键字 语法糖

    原文地址:http://www.cnblogs.com/santian/p/4389675.html 对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味 ...

  8. Python之路:迭代器和yield生成器

    一.迭代器 对于Python 列表的 for 循环,他的内部原理:查看下一个元素是否存在,如果存在,则取出,如果不存在,则报异常 StopIteration.(python内部对异常已处理) 使用迭代 ...

  9. C#2.0中使用yield关键字简化枚举器的实现

    我们知道要使用foreach语句从客户端代码中调用迭代器,必需实现IEnumerable接口来公开枚举器,IEnumerable是用来公开枚举器的,它并不实现枚举器,要实现枚举器必需实现IEnumer ...

随机推荐

  1. Java8新特性——新一套时间API的使用

    JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了.而Calendar并不比Date好多少.它们面临的问题是: 可变性: ...

  2. ASP.NET MVC EF 连接数据库(一)-----Database First

    database first (VS2015 ,Sql Server2014) 1,新建MVC项目 实例:   源码代码:http://note.youdao.com/noteshare?id=1fd ...

  3. Python itertools 操作迭代对象

    Python 的内建模块itertools提供了很多操作迭代对象的方法 参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/101778314 ...

  4. Java网上体育商城系统ssh

    网上体育商城的主要功能包括:前台用户登录退出.注册.在线购物.修改个人信息.后台商品管理等等.本系统结构如下:(1)商品浏览模块:        首页浏览最新上市商品,按销量排行显示商品        ...

  5. 浅析java线程和OS线程的关系

    探究java线程和OS线程之间的联系 一.准备工作 1.查看linux创建线程的方法    man pthread_create 根据man的配置可知,pthread_create会创建一个线程,这个 ...

  6. ASP.NET Core系列:日志

    1. NLog 添加安装包: Install-Package NLog.Web.AspNetCore <?xml version="1.0" encoding="u ...

  7. 设计模式:单例模式(singleton)

    singleton模式属于创建型设计模式.其作用是在程序设计中,对于某一个类而言,全局只能存在一个实例对象. 下面以C++为例,对单例模式进行说明: 1. 最基本单例模式(单线程) class Sin ...

  8. Ubuntu启动器快捷方式文件解析

    快捷方式名称 app_name.desktop 路径: /usr/share/applications/app_name.desktop # 简洁快捷方式格式 [Desktop Entry] Name ...

  9. JVM 对象查询语言(OQL)[转载]

    最近生产环境出现一个很奇怪的问题,测试环境无法重现,本地直连生产无法重现.于是用上 jmap + Java VisualVM 的 OQL (Object Query Language) 分析问题. 关 ...

  10. conan使用(四)--打包二进制库

    前面总结过如何打包一个存头文件库,那种情况下非常简单,因为只需要将源文件拷贝就行了.现在来研究下如何打包一个正常情况下会生成动态库或静态库的包.参考文档:https://docs.conan.io/e ...