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 ...
随机推荐
- Lambda 表达式构建初级示例(不完整)
直接贴代码了: using System; using System.Collections.Generic; using System.Linq; using System.Linq.Express ...
- laravel模型中非静态方法也能静态调用的原理
刚开始用laravel模型时,为了方便一直写静态方法,进行数据库操作. <?php namespace App\Models; use Illuminate\Database\Eloquent\ ...
- 第五篇 openvslam建图与优化模块梳理
建图模块 mapping_module在初始化系统的时候进行实例化,在构建实例的时候会实例化local_map_cleaner和local_bundle_adjuster.系统启动的时候会在另外一个线 ...
- c++和java的一些debug方法
就上面那个绿色的小瓢虫,点了就进了debug模式. 好尴尬啊,就说一句话. 而且,要加断点,不然就一下debug完了.
- mssql 导出作业,导出表,导出存储过程等
1.mssql 导出作业 1.选中sql server 代理-作业 2.点击F7 显示对象资源管理器详细信息,3.按住ctrol 选中 右键编写作业脚本到就可以了 2.mssql 导出表和存储过程等 ...
- docker 制作一个容器,并上传到仓库
创建镜像的三种方法 1.基于已有的镜像的容器创建 启动一个容器并修改容器: docker run -it ubuntu:latest /bin/bash touch test 提交创建新镜像并查看制作 ...
- 个人项目(WC.exe)(java)(基于图形界面)
一.Github项目地址:https://github.com/Leungdc/ENhomework 二.PSP: PSP2.1 Personal Software Process Stages 预估 ...
- Fundebug录屏插件更新至0.5.0,新增domain参数
摘要: 通过配置domain来保证"视频"的正确录制 录屏功能介绍 Fundebug提供专业的异常监控服务,当线上应用出现 BUG 的时候,我们可以第一时间报警,帮助开发者及时发现 ...
- Django ajax 检测用户名是否已被注册
添加一个 register.html 页面 <!DOCTYPE html> <html lang="en"> <head> <meta c ...
- VMware虚拟机可与Win10物理机互ping并可访问互联网的设置方法
一.系统环境: VMware 15.Windows 10 1903.Windows 7 虚拟机 二.具体步骤: 1.Win10物理机,控制面板-所有控制面板项-网络连接-物理网卡适配器右键-属性-共 ...