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 ...
随机推荐
- WinForm 程序在系统托盘显示
前言 有些程序在关闭或最小化的时候会隐藏在系统托盘中,双击或右击会重新显示,winform实现其功能很简单,这边就简单的介绍下. 实现 在winform实现托盘使用notifyIcon控件,如果加菜单 ...
- VM1059 bootstrap-table.min.js:7 Uncaught TypeError: Cannot read property 'classes' of undefined
参考链接:https://blog.csdn.net/liuqianspq/article/details/81868283 1.阳光明媚的下午,我在写CRUD,让数据传到前端的时候,解析的时候报错了 ...
- VS2013(InstallShield2015LimitedEdition)打包程序详解
VS2012没有自带打包工具,所以要先下载并安装一个打包工具.我采用微软提供的打包工具: InstallShield2015LimitedEdition.下载地址:https://msdn.micr ...
- jakarta-oro-2.0.8.jar-----------JAVA FTP相关
资源不好找,找到了就和大家分享一下! 链接:https://share.weiyun.com/51kBB0y 密码:2hcxcu
- 基于WEB的网上购物系统-ssh源码
基于WEB的网上购物系统主要功能包括:前台用户登录退出.注册.在线购物.修改个人信息.后台商品管理等等.本系统结构如下:(1)商品浏览模块: 实现浏览最新商品 实现按商品名 ...
- HighChat动态绑定数据 数据后台绑定(四)
后台绑定数据,直接返回json数据 IList<SummaryHour> adHourData = summarybll.FindList(str); List<, , , , , ...
- Oracle 11g 手工建库
假设数据库软件已经安装好,现在没有图形界面无法用dbca安装数据库,那么用手工建库,数据库名为edw 创建目录 [oracle@localhost ~]$ mkdir -p /u01/app/orac ...
- sql server 安装出现需要sqlncli.msi文件,错误为 microsoft sql server 2012 native client
在安装sql server 2017 时出现 弹框标题为 microsoft sql server 2012 native client 内容为需要sqlncli.msi文件 去本地目录找本身的那 ...
- liteos错误处理(十一)
1. 概述 1.1 基本概念 错误处理指用户代码发生错误时,系统调用错误处理模块的接口函数,完成上报错误信息,并调用用户自己的钩子函数,进行特定的处理. 错误处理模块实现OS内部错误码记录功能.OS内 ...
- 很不错的python 机器学习资源
http://www.cuijiahua.com/resource.html 曾看过的书,感觉一些很有用的学习资料,推荐给大家! Python基础: 网络教程推荐: 系统学习python3可以看廖雪峰 ...