C# 迭代器与yield关键字
迭代器模式是设计模式的一种,因为其运用的普遍性,很多语言都有内嵌的原生支持
在.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关键字的更多相关文章
- yield 关键字和迭代器
一般使用方法 yield 关键字向编译器指示它所在的方法是迭代器块 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值. 这是一个返回值,例如,在 forea ...
- Python:容器、迭代对象、迭代器、生成器及yield关键字
在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(generator).列表/集合/字典推导式(list, ...
- C#使用yield关键字构建迭代器
http://www.cnblogs.com/Huaran1chendu/p/4838536.html 以前,如果我们希望构建支持foreach枚举的自定义集合,只能实现IEnumerable接口(可 ...
- 使用yield关键字让自定义集合实现foreach遍历
一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...
- (转) Python Generators(生成器)——yield关键字
http://blog.csdn.net/scelong/article/details/6969276 生成器是这样一个函数,它记住上一次返回时在函数体中的位置.对生成器函数的第二次(或第 n 次) ...
- 转载yield关键字理解
实现IEnumerable接口及理解yield关键字 [摘要]本文介绍实现IEnumerable接口及理解yield关键字,并讨论IEnumerable接口如何使得foreach语句可以使用. 本 ...
- C# 基础小知识之yield 关键字 语法糖
原文地址:http://www.cnblogs.com/santian/p/4389675.html 对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味 ...
- Python之路:迭代器和yield生成器
一.迭代器 对于Python 列表的 for 循环,他的内部原理:查看下一个元素是否存在,如果存在,则取出,如果不存在,则报异常 StopIteration.(python内部对异常已处理) 使用迭代 ...
- C#2.0中使用yield关键字简化枚举器的实现
我们知道要使用foreach语句从客户端代码中调用迭代器,必需实现IEnumerable接口来公开枚举器,IEnumerable是用来公开枚举器的,它并不实现枚举器,要实现枚举器必需实现IEnumer ...
随机推荐
- linux bash 的基础语法
示例均来自网络,附带有原始链接地址,自己练习整理发出,均测试可用 linux shell 基本语法 - 周学伟 - 博客园 https://www.cnblogs.com/zxouxuewei/p/6 ...
- 关于VS2017离线安装的一点扩充说明
转自:https://www.cnblogs.com/dunitian/p/8051985.html 其实逆天不推荐自己慢慢离线,找个离线包更新下再打包更快 Key:http://www.cnblog ...
- Spring源码系列 — 构造和初始化上下文
探索spring源码实现,精华的设计模式,各种jdk提供的陌生api,还有那么点黑科技都是一直以来想做的一件事!但是读源码是一件非常痛苦的事情,需要有很大的耐心和扎实的基础. 在曾经读两次失败的基础上 ...
- laravel 广播细节讲解
1.应用场景 1.通知(Notification) 或 信号(Signal) 2.通知是最简单的示例,也最经常用到.信号也可看作是通知的一种展现形式,只不过信号没有UI而已. 3.Activity S ...
- IIS Express 启用目录浏览 方法
标签: iis / visual studio / C# / ASP.NET / .NET 522 今天刚刚使用visual studio 2013创建第一个hello world,结果就发现提示错误 ...
- C# WebAPI 文件在线预览
最近在写一个移动端API接口,其中有一个需求:接口返回附件url地址让手机端调用实现文件在线预览.大体实现思路:把doc.xls等文本格式文件转换为pdf,转换后的pdf文件存放在服务器上面,方便第二 ...
- Vs2017发布可在线更新的Winform程序
如题,此处引用“南秦岭”的博文<使用ClickOnce发布Windows应用程序>,对作者表示感谢! 补充说明: “发布文件夹”是指你电脑上的本地文件夹:“安装文件夹”是指你提供给用户的u ...
- Linux打包和压缩——管理打包和压缩的命令
Linux打包和压缩——管理打包和压缩的命令 摘要:本文主要学习了Linux的打包命令和压缩命令. tar命令 tar命令可以用来进行打包和解打包,压缩和解压缩. 基本语法 打包和压缩的语法: tar ...
- 安装配置ZooKeeper及基本用法
要想学习分布式应用,ZooKeeper是一个绕不过去的基础系统.它为大型分布式计算提供开源的分布式配置服务.同步服务和命名注册. 今天先介绍系统的安装和基本使用,后续会推一些基本的Java使用代码. ...
- window10 蓝牙怎么连接音响或蓝牙耳机
window10 蓝牙怎么连接音响或蓝牙耳机 1.在电脑上依次点击win图标右键-->设置,打开系统设置窗口. 2.点击“设备”,在窗口左侧选择“蓝牙”,右侧检查并开启电脑的蓝牙设备开关, 3. ...