转载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(): ... ...
随机推荐
- codeforces 235 div2 C Team
题目:http://codeforces.com/contest/401/problem/C 题意:n个0,m个1,求没有00或111的情况. 这么简单的题..... 做题的时候脑残了...,今天,贴 ...
- crontab无法调用java的问题解决
本来想将写的代码挂在crontab下运行,谁知道无法运行,没有任何输出,试着用ls -al >> 1.log试了一下,确定crontab是正常运行的. 从网站上找了下问题,原因出在cron ...
- HDU 1711 (裸KMP) Number Sequence
题意: 用第二个数列去匹配第一个数列,输出第一次匹配到的位置,如果没有则输出-1. 分析: 这明显是一道裸的KMP. 我是在这篇博客上学的KMP算法的,讲得比较透彻. http://blog.csdn ...
- SDOI 2010 and SXOI 2014 地精部落 (递推)
用E[i,j]表示共有i个数字,以1..j开头且一开始下降的方案数的总和.则我们有: E[i,j]:=E[I,J-1]+E[i-1,i-j] 我们先来证明上升与下降的方案是一一对应的. 事实上,若有a ...
- tomcat调优的几个方面
转载自:http://my.oschina.net/u/593721/blog/146710 作者:小报童 和早期版本相比最新的Tomcat提供更好的性能和稳定性.所以一直使用最新的Tomcat版本. ...
- 【大数比较】NYOJ-73
比大小 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描述 给你两个很大的数,你能不能判断出他们两个数的大小呢? 比如123456789123456789要大于-1234 ...
- System.arraycopy方法
数组的复制有多种方法,其中有一种就是System.arraycopy方法,传闻速度也很快. 方法完整签名: public static void arraycopy(Object src, int s ...
- Android如何调用第三方SO库
问题描述:Android如何调用第三方SO库:已知条件:SO库为Android版本连接库(*.so文件),并提供了详细的接口说明:已了解解决方案:1.将SO文件直接放到libs/armeabi下,然后 ...
- MySQL基础之第13章 MySQL函数
13.1.数学函数 随机数可能会用到,其他基本无视. 13.2.字符串函数 重点CONCAT(S1,S2….) 13.3.日期和时间函数 一.MySQL 获得当前日期时间 函数 1.1 获得当前日期+ ...
- win7和centos双系统安装
几年之前为了安装xp和linux的双系统曾折腾了好多天,今天为了安装这个win7和centos双系统,也折腾了两天多,哦,我的天,安装个双系统,怎么这么麻烦呢? 没有来得及整理,先铺上草稿,供同志们参 ...