转载yield关键字理解
实现IEnumerable接口及理解yield关键字
[摘要]本文介绍实现IEnumerable接口及理解yield关键字,并讨论IEnumerable接口如何使得foreach语句可以使用。
本文讨论题目的内容。然后讨论IEnumerable接口如何使得foreach语句可以使用。之后会展示如果实现自定义的集合类,该集合类实现了IEnumerable接口。Yield关键字和遍历集合后面也讨论。
背景
一使用集合。就发现遍历集合就跟着来了。遍历集合最好的方式是实现迭代器模式-Understanding and Implementing the Iterator Pattern in C# and C++ ,C#提供foreach来以一种优雅的方式遍历。
只要集合实现了IEnumerable 接口就可以用foreach来遍历。
使用代码
首先先看一下内置的集合类如何使用foreach来遍历的。ArrayList实现了IEnumerable 接口。我们看一下:
1
2
3
4
5
6
7
8
9
10
11
12
|
// 看一下实现了IEnumerable 接口的集合如何遍历 ArrayList list = new ArrayList(); list.Add( "1" ); list.Add(2); list.Add( "3" ); list.Add( '4' ); foreach ( object s in list) { Console.WriteLine(s); } |
遍历泛型集合类
Arraylist 是一个通用集合类,遍历泛型集合类也可以。因为这些泛型集合类实现了IEnumerable<T>接口,看一下吧。
1
2
3
4
5
6
7
8
9
10
11
12
|
// 遍历实现了IEnumerable<T>接口的泛型类 List< string > listOfStrings = new List< string >(); listOfStrings.Add( "one" ); listOfStrings.Add( "two" ); listOfStrings.Add( "three" ); listOfStrings.Add( "four" ); foreach ( string s in listOfStrings) { Console.WriteLine(s); } |
发现了吧。我们自定义的集合类或是泛型集合类应该实现IEnumerable和IEnumerable<T>接口。这样就可以遍历了。
理解yield关键字
在写个实现接口的例子之前,先理解一下yield关键字,yield会记录集合位置。当从一个函数返回一个值的时候,yield可以用。
如下的普通的方法。不论调用多少次,都只会返回一个return。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
static int SimpleReturn() { return 1; return 2; return 3; } static void Main( string [] args) { // 看看 Console.WriteLine(SimpleReturn()); Console.WriteLine(SimpleReturn()); Console.WriteLine(SimpleReturn()); Console.WriteLine(SimpleReturn()); } |
原因就是普通的return语句不保留函数的返回状态。每一次都是新的调用。然后返回第一个值。
但是使用下面的语句替换后就不一样。当函数第二次调用的时候。会从上次返回的地方继续调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
static IEnumerable< int > YieldReturn() { yield return 1; yield return 2; yield return 3; } static void Main( string [] args) { // 看看yield return的效果 foreach ( int i in YieldReturn()) { Console.WriteLine(i); } } |
显然返回1,2,3,唯一要注意的就是函数需要返回IEnumerable。,然后通过foreach调用。
在自定义的集合类里实现Ienumerable接口
现在如果我们在我们的自定义集合里定义一个方法。来迭代所有元素。然后通过使用yield返回。我们就可以成功了。
好。我们定义MyArrayList 类,实现IEnumerable 接口,该接口就会强制我们实现GetEnumerator 函数。这里我们就要使用yield了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class MyArrayList : IEnumerable { object [] m_Items = null ; int freeIndex = 0; public MyArrayList() { // 对了方便我直接用数组了,其实应该用链表 m_Items = new object [100]; } public void Add( object item) { // 考虑添加元素的时候 m_Items[freeIndex] = item; freeIndex++; } // IEnumerable 函数 public IEnumerator GetEnumerator() { foreach ( object o in m_Items) { // 检查是否到了末尾。数组的话。。。没写好 if (o == null ) { break ; } // 返回当前元素。然后前进一步 yield return o; } } } |
之后你就可以用foreach遍历了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
static void Main( string [] args) { //看看调用部分 MyArrayList myList = new MyArrayList(); myList.Add( "1" ); myList.Add(2); myList.Add( "3" ); myList.Add( '4' ); foreach ( object s in myList) { Console.WriteLine(s); } } |
这个类啊。没写好。也不完整。只要是让你理解。。模拟一下而已。
自定义泛型类里实现Ienumerable<T>接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
class MyList<T> : IEnumerable<T> { T[] m_Items = null ; int freeIndex = 0; public MyList() { // 为了方便。使用数组 m_Items = new T[100]; } public void Add(T item) { //添加元素 m_Items[freeIndex] = item; freeIndex++; } #region IEnumerable<T> Members public IEnumerator<T> GetEnumerator() { foreach (T t in m_Items) { //检查是否到了末尾。数组的话。。。没写好 if (t == null ) // 如果T不是一个可空类型。就中断 { break ; } // 返回当前元素,然后前进一步 yield return t; } } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { // 此处调用泛型版本 return this .GetEnumerator(); } #endregion } |
之后就可以使用foreach了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
static void Main( string [] args) { // 使用示例 MyList< string > myListOfStrings = new MyList< string >(); myListOfStrings.Add( "one" ); myListOfStrings.Add( "two" ); myListOfStrings.Add( "three" ); myListOfStrings.Add( "four" ); foreach ( string s in myListOfStrings) { Console.WriteLine(s); } } |
转载yield关键字理解的更多相关文章
- C#中yield关键字理解
yield关键字之前用得较少,但是在做项目开发的过程中也遇到了,当时有点迷惑,就顺便研究学习了一下,以下是个人理解,不到之处欢迎拍砖!废话就到这,上代码: class Program { static ...
- [原译]实现IEnumerable接口&理解yield关键字
原文:[原译]实现IEnumerable接口&理解yield关键字 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享.请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢 ...
- 深入理解python中的yield关键字
想必大家都看过这样的代码: 上面的这段代码会计算0-9的平方并打印出来. 那么问题来了,这段代码和我们要说的东西有什么区别呢? 这里的关键字,yield,我在前面的文章里已经发过了.那么yield是什 ...
- 理解 ES6 语法中 yield 关键字的返回值
在 ES6 中新增了生成器函数的语法,本文解释了生成器函数内 yield 关键字的返回值. 描述 根据语法规范,yield 关键字用来暂停和继续执行一个生成器函数.当外部调用生成器的 next() 方 ...
- 理解 ES6 语法中 yield* 关键字的作用
在 ES6 中新增了生成器函数的语法,本文解释了与生成器函数有关的 yield* 关键字,及其使用场景. 描述 根据语法规范,yield* 的作用是代理 yield 表达式,将需要函数本身产生(yie ...
- C# 基础小知识之yield 关键字 语法糖
原文地址:http://www.cnblogs.com/santian/p/4389675.html 对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味 ...
- C# 基础小知识之yield 关键字
对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味着它在其中出现的方法.运算符或 get 访问器是迭代器. 通过使用 yield 定义迭代器,可在实现自 ...
- 解析Python中的yield关键字
前言 python中有一个非常有用的语法叫做生成器,所利用到的关键字就是yield.有效利用生成器这个工具可以有效地节约系统资源,避免不必要的内存占用. 一段代码 def fun(): for i i ...
- python yield 关键字
最近看代码看到python里面的yield关键字,和我之前接触的语言好像都没有来着,我就查了查它的含义,大概理解如下: >>> def createGenerator(): ... ...
随机推荐
- 用imagemagick和tesseract-ocr破解简单验证码
用imagemagick和tesseract-ocr破解简单验证码 Tesseract-ocr据说辨识程度是世界排名第三,可谓神器啊. 准备工作: 1.安装tesseract-ocr sudo apt ...
- poj 2948 Martian Mining (dp)
题目链接 完全自己想的,做了3个小时,刚开始一点思路没有,硬想了这么长时间,想了一个思路, 又修改了一下,提交本来没抱多大希望 居然1A了,感觉好激动..很高兴dp又有所长进. 题意: 一个row*c ...
- HDU4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)
Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- fil_space_t
typedef struct fil_space_struct fil_space_t; /** Tablespace or log data space: let us call them by a ...
- JAVA安卓和C# 3DES加密解密的兼容性问题(2013年8月修改版)
近 一个项目.net 要调用JAVA的WEB SERVICE,数据采用3DES加密,涉及到两种语言3DES一致性的问题, 下面分享一下, 这里的KEY采用Base64编码,便用分发,因为Java的By ...
- 运维角度浅谈MySQL数据库优化(转)
一个成熟的数据库架构并不是一开始设计就具备高可用.高伸缩等特性的,它是随着用户量的增加,基础架构才逐渐完善.这篇博文主要谈MySQL数据库发展周期中所面临的问题及优化方案,暂且抛开前端应用不说,大致分 ...
- LeetCode: divideInteger
Title: Divide two integers without using multiplication, division and mod operator. If it is overflo ...
- windows主线程等待子线程退出卡死问题
在windows下调用_beginthread创建子线程并获得子线程id(函数返回值),如果子线程很快退出,在主线程中调用WaitForSingleObject等待该线程id退出,会导致主线程卡死.需 ...
- POJ 2421 Constructing Roads
题意:要在n个城市之间建造公路,使城市之间能互相联通,告诉每个城市之间建公路的费用,和已经建好的公路,求最小费用. 解法:最小生成树.先把已经建好的边加进去再跑kruskal或者prim什么的. 代码 ...
- 六款最佳Linux教育应用
导读 对教育行业的用户来说,有好几款专门的Linux发行版是专门面向教育行业的.本文将介绍适合教育领域的几款顶级发行版. 1.Edubuntu 位居榜首的是Edubuntu.顾名思义,Edubuntu ...