【转】C#学习之用迭代器实现枚举器
http://www.cnblogs.com/zouzf/archive/2012/02/22/2362954.html
本人初学C#,本文仅供个人整理思路用,那里说得不对,请大家多多指教,万分感激!
上一篇文章为自定义类实现了foreach的功能,但实现过程中要实现IEnumerator接口(包括MoveNext、Reset函数和Current属性)以便GetEnumerator函数能获取枚举数,有点复杂,有点繁琐。
已经知道:主要一个类实现了GetEnumerator函数就能foreach,而实现IEnumerator接口只是实现GetEnumerator函数的其中一个办法,也就说还有其他办法实现GetEnumerator函数了?是的,C#2.0为我们提供了一种很简单的方法来实现GetEnumerator函数,那就是使用迭代器!(还记得吧,C#里的迭代器和C++里的是不同的)
下面是来自MSDN的解说:
迭代器概述
迭代器是可以返回相同类型的值的有序序列的一段代码。
迭代器可用作方法、运算符或 get 访问器的代码体。
迭代器代码使用 yield return 语句依次返回每个元素。yield break 将终止迭代。有关更多信息,请参见 yield。
可以在类中实现多个迭代器。每个迭代器都必须像任何类成员一样有唯一的名称,并且可以在 foreach 语句中被客户端代码调用,如下所示:foreach(int x in SampleClass.Iterator2){}
迭代器的返回类型必须为 IEnumerable、IEnumerator、IEnumerable<T> 或 IEnumerator<T>。
yield 关键字用于指定返回的值。到达 yield return 语句时,会保存当前位置。下次调用迭代器时将从此位置重新开始执行。
第一部分:使用默认迭代器实现获取枚举数
1、定义Person类
复制代码
1 public class Person
2 {
3 public string Name;
4 public int Age;
5
6 public Person(string name, int age)
7 {
8 Name = name;
9 Age = age;
10 }
11
12 public override string ToString()
13 {
14 return "Name: " + Name + "\tAge: " + Age;
15 }
16 }
复制代码
2、定义PeopleEnum1类,里面实现了GetEnumerator函数(也就是迭代器了,这是默认的迭代器),但实现的过程相对于上一篇文章里介绍的实现过程要简单很多,这就是yield的功效。yield的实现原理这里就不详说了,可以概括为:GetEnumerator函数里的迭代块把 IEnumerator接口的MoveNext、Reset方法和Current属性封装了,但本质没变,只是我们使用起来更方便了。
复制代码
1 public class PeopleEnum1
2 {
3 private Person[] _perple;
4
5 //构造函数
6 public PeopleEnum1(Person[] list)
7 {
8 _perple = new Person[list.Length];
9 for (int i = 0; i < list.Length; i++)
10 {
11 _perple[i] = list[i];
12 }
13 }
14
15 public IEnumerator GetEnumerator()
16 {
17 for (int i = 0; i < _perple.Length; i++)
18 {
19 yield return _perple[i];
20 }
21 }
22
23 }
复制代码
3、主函数代码
复制代码
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Person[] persons = new Person[]
6 {
7 new Person("aaa", 20),
8 new Person("bbb", 21),
9 new Person("ccc", 22)
10 };
11
12 PeopleEnum1 peopleEnum = new PeopleEnum1(persons);
13
14 foreach (var item in peopleEnum)
15 {
16 System.Console.WriteLine(item);
17
18 }
19
20 System.Console.ReadKey();
21 }
22 }
复制代码
运行,成功,嘿嘿
第二部分:自定义迭代器
第一部分用默认迭代器GetEnumerator 实现了类的foreach,我们也可以定义自己的迭代器来获取自己想要的枚举数。比较说,我想列举出类中未成年人的信息,默认的迭代器无能为力,该怎么实现自定义的迭代器呢?
1、为PeopleEnum1类添加一个迭代器 GetChildren ,在这里,这个迭代器是一个属性,也可以定义为函数。对于类中的元素,只有Age 小于18的元素才 yield return ,其他的不要。
复制代码
1 public class PeopleEnum1
2 {
3 private Person[] _perple;
4
5 //构造函数
6 public PeopleEnum1(Person[] list)
7 {
8 _perple = new Person[list.Length];
9 for (int i = 0; i < list.Length; i++)
10 {
11 _perple[i] = list[i];
12 }
13 }
14
15 //默认的迭代器?
16 public IEnumerator GetEnumerator()
17 {
18 for (int i = 0; i < _perple.Length; i++)
19 {
20 yield return _perple[i];
21 }
22 }
23
24
25 //自定义迭代器
26 public IEnumerable GetChildren
27 {
28 get
29 {
30 for (int i = 0; i < _perple.Length; i++)
31 {
32 if (_perple[i].Age < 18)
33 {
34 yield return _perple[i];
35 }
36 }
37 }
38 }
39 }
复制代码
2、主函数代码
复制代码
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Person[] persons = new Person[]
6 {
7 new Person("aaa", 16),
8 new Person("bbb", 18),
9 new Person("ccc", 22)
10 };
11
12
13 PeopleEnum1 peopleEnum = new PeopleEnum1(persons);
14
15 foreach (var item in peopleEnum)
16 {
17 System.Console.WriteLine(item);
18 }
19
20
21 Console.WriteLine("\n集合中未成年人的信息");
22
23 foreach (var item in peopleEnum.GetChildren)
24 {
25 Console.WriteLine(item);
26 }
27
28 System.Console.ReadKey();
29 }
30 }
复制代码
输出结果:
输出结果:

可以看到,自定义的迭代器 GetChildren 成功foreach了。
注意:默认迭代器 GetEnumerator 的返回类型是 IEnumerator ,并且在使用foreach时 in 后面直接是类名。而自定义迭代器 GetChildren 的返回类型是 IEnumerable,并且在使用foreach时 in 后面是 PeopleEnum.GetChildren(类名.迭代器名)。好像,好像是规定这样子的,原理是什么还不清楚。
【转】C#学习之用迭代器实现枚举器的更多相关文章
- python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化
生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...
- STL学习笔记(迭代器配接器)
Reverse(逆向)迭代器 Reverse迭代器是一种配接器. 重新定义递增运算和递减运算.使其行为正好倒置. 如果你使用这类迭代器,算法将以逆向次序处理元素.所有标准容器都允许使用Reverse迭 ...
- C#图解教程 第十八章 枚举器和迭代器
枚举器和迭代器 枚举器和可枚举类型 foreach语句 IEnumerator接口 使用IEnumerable和IEnumerator的示例 泛型枚举接口迭代器 迭代器块使用迭代器来创建枚举器使用迭代 ...
- ruby迭代器枚举器
迭代器一个迭代器是一个方法,这个方法里面有yield语句,使用了yield的方法叫做迭代器,迭代器并非一定要迭代,与传递给这个方法的块进行数据传输 yield将数据传给代码快,代码块再把数据传输给yi ...
- ruby中迭代器枚举器的理解
参考<ruby编程语言>5.3迭代器和可枚举对象 迭代器一个迭代器是一个方法,这个方法里面有yield语句,这个方法里的yield语句,与传递给这个方法的块进行数据传输 yield将数据传 ...
- ruby迭代器iterator和枚举器Enumerator
编写自定义的迭代器 The defining feature of an iterator method is that it invokes a block of code associatedwi ...
- 【转】Java学习之Iterator(迭代器)的一般用法 (转)
[转]Java学习之Iterator(迭代器)的一般用法 (转) 迭代器(Iterator) 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭 ...
- C# 枚举器和迭代器
一.枚举器(enumerator)和可枚举类型(enumeration) 我们都知道foreach语句可以用来遍历数组中的元素,但你有没有想过为什么它可以被foreach处理呢? 这是因为数组可以按需 ...
- C#知识点-枚举器和迭代器
一.几个基本概念的理解 问题一:为什么数组可以使用foreach输出各元素 答:数组是可枚举类型,它实现了一个枚举器(enumerator)对象:枚举器知道各元素的次序并跟踪它们的位置,然后返回请求的 ...
随机推荐
- CentOS7.3+MySQL5.7+Apache2.4+PHP7.1+phpMyAdmin4.7+JDK1.8+SVN1.6+Jenkins2.1环境搭建
CentOS7.3+MySQL5.7+Apache2.4+PHP7.1+phpMyAdmin4.7+JDK1.8+SVN1.6+Jenkins2.1环境搭建 1.安装CentOS7.3虚拟机安装说明: ...
- 【TensorFlow入门完全指南】模型篇·线性回归模型
首先呢,进行import,对于日常写代码来说,第二行经常写成:import numpy as np,这样会更加简洁.第三行import用于绘图. 定义了学习率.迭代数epoch,以及展示的学习步骤,三 ...
- Predicate和Consumer接口的使用
// Predicate 判断是否拥有资格,Consumer 改变输入的值 案例 public static MyTest2 getV(MyTest2 a, Predicate<MyTe ...
- Lemonade Trade
4990: Lemonade Trade 时间限制: 1 Sec 内存限制: 128 MB Special Judge提交: 88 解决: 17[提交][状态][讨论版][命题人:admin] ...
- MFC:AfxSetResourceHandle
AfxGetResourceHandle用于获取当前资源模块句柄. 而AfxSetResourceHandle则用于设置程序目前要使用的资源模块句柄,一般在InitInstance()里调用.
- cppoop作业:Inheritance+Composition 關係下的構造和析構
Inheritance+Composition 關係下的構造和析構 哪个的ctor先被调用. 父类先于组件类调用 构造函数
- Java 的Throwable、error、exception的区别
1. 什么是异常? 异常本质上是程序上的错误,包括程序逻辑错误和系统错误.比如使用空的引用(NullPointerException).数组下标越界(IndexOutOfBoundsException ...
- 【启发式拆分】bzoj4059: [Cerc2012]Non-boring sequences
这个做法名字是从武爷爷那里看到的…… Description 我们害怕把这道题题面搞得太无聊了,所以我们决定让这题超短.一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,即每个子 ...
- DeepFaceLab小白入门(6):脸部替换以及合成视频!
前面的都是准备工作,这个环节才是真的换脸.换脸主要分两部分,1,图片换脸,2,把图片合成视频. 7) convert H64 debug.bat 这个环节是和训练环节相对于的,比如我们之前选的是H64 ...
- ProC第三弹
一.前言 我们上面已经了解Windows和Linux下的ProC开发环境,这里我们更进一步去简要介绍下ProC的预编译参数. 二.什么是预编译 预编译过程中,Pro*C/C++会自动生成C或者C++的 ...