转载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(): ... ...
随机推荐
- poj 1905 Expanding Rods (数学 计算方法 二分)
题目链接 题意:将长度为L的棒子卡在墙壁之间.现在因为某种原因,木棒变长了,因为还在墙壁之间,所以弯成了一个弧度,现在求的是弧的最高处与木棒原先的地方的最大距离. 分析: 下面的分析是网上别人的分析: ...
- struts.custom.i18n.resources 如何配置多个资源文件?
struts.custom.i18n.resources = resources1,resources2,resources3 配置properties文件
- Firefox和Chrome浏览器导出书签
Chrome浏览器: 或者直接在地址栏中输入:“chrome://bookmarks/#1”也可以 Firefox浏览器:
- UVa 1103 (利用连通块来判断字符) Ancient Messages
本题就是灵活运用DFS来求连通块来求解的. 题意: 给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符.然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号. 分析: 首先图像是被 ...
- fastdfs-client-java 文件上传
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文件为载体的在线服务,如相 ...
- hdu 4607 Park Visit(树上最长链)
求树上最长链:两遍搜索. 第一次从树上任意点开始,最远点必然是某一条最长链上的端点u. 第二次从u开始,最远点即该最长链的另一端点. 先在最长链上走,不足再去走支链. 把询问数m错打成n,狠狠wa了一 ...
- 苹果官方 Crash文件分析方法 (iOS系统Crash文件分析方法)
对于提交的苹果官方的app,在审核的时候会给我们一些crash文件,对于这些有用的文件,里面是关于我们的bug的一些信息,那么该如何去调试呢 第一步:在任意目录创建一个目录,用来调试crash,我这里 ...
- h.264码流解析_一个SPS的nalu及获取视频的分辨率
00 00 00 01 67 42 00 28 E9 00 A0 0B 77 FE 00 02 00 03 C4 80 00 00 03 00 80 00 00 1A 4D 88 10 94 0 ...
- poj 3694 Network
题意: 添加每条新连接后网络中桥的数目// 超时 先放着了 ,下次改//早上这代码超时了 下午改了,代码在下面#include <iostream> #include <algori ...
- MYSQL设计方案
Scale Out:横向扩展,增加处理节点提高整体处理能力Scale Up:纵向扩展,通过提升单个节点的处理能力达到提升整体处理能力的目的 ReplicationMySQL的replication是异 ...