一、枚举器(enumerator)和可枚举类型(enumeration)

  我们都知道foreach语句可以用来遍历数组中的元素,但你有没有想过为什么它可以被foreach处理呢?

  这是因为数组可以按需提供一个叫做枚举器的对象,枚举器“知道”项的次序并且跟踪它在序列中的位置,然后返回请求的当前项,所以可以依次遍历数组

  你可以通过调用对象的GetEnumerator方法来获取它的枚举器,实现了GetEnumerator方法的类型叫做可枚举类型,毫无疑问,数组是可枚举类型

二、IEnumerator接口和IEnumerable接口

 1.IEnumerator接口

  实现了IEnumerator接口的枚举器包含三个函数成员

    a: Current  它是返回序列中当前位置项的属性,并且是只读的,返回object类型的引用

    b: MoveNext()  它是把枚举器位置前进到集合中下一项的方法,返回布尔值用来指示下一项的位置是否有效,有效返回true,否则返回false

               需要注意的是,枚举器的原始位置在第一项之前(下标从0开始的话,也可以理解为-1的位置),因此MoveNext()必须在第一次使用Current之前调用

    c: Reset()  把位置重置为原始状态的方法

  让我们通过模仿foreach演示一下如何使用

using System;
using System.Collections;
using System.Collections.Generic; namespace 枚举器
{
class Program
{
static void Main(string[] args)
{
int[] arr = { , , , };
IEnumerator ie = arr.GetEnumerator(); //获取枚举器
while (ie.MoveNext()) //移动到下一项
{
Console.Write("{0} ", ie.Current); //获取当前项的值
}
ie.Reset(); //重置
Console.ReadKey();
}
}
}

和foreach结果一样,为:  1 3 5 7

扩展一点,foreach遍历可枚举对象时,它会调用GetEnumerator方法获取对象的枚举器,然后再从枚举器中申请每一项作为迭代变量,代码可以读取该变量,但不能改变它

 2.IEnumerable接口

  可枚举类型是指实现了IEnumerable接口的类。IEnumerable接口只有一个成员---------GetEnumerator方法,它返回对象的枚举器

class MyColor : IEnumerable
{
string[] color = { "red", "green", "yellow" };
public IEnumerable GetEnumerator()
{
return new ColorEnum(color); //ColorEnum()为枚举器类的实例
}
}

三、泛型枚举接口

  前面的枚举接口都是非泛型版本,实际上大多数情况下都应该使用泛型版本IEnumerable<T>和IEnumerator<T>(关于泛型你可以看一下我之前写过的博客),介绍一下它们之间的差别

a: 非泛型接口形式

  IEnumerable接口的GetEnumerator方法返回的是IEnumerator枚举器类的实例;

  实现IEnumerator的类实现了Current属性,它返回object的引用,我们必须把它转换成实际类型的对象

b: 泛型接口形式

  IEnumerable<T>接口的GetEnumerator方法返回的是IEnumerator<T>枚举器类的实例;

  实现IEnumerator<T>的类实现了Current属性,它返回实际类型的引用,而不是object基类的引用

需要注意的是,我们目前所看到的非泛型接口的枚举类型是不安全的,它们返回object类型的引用必须转化为实际类型,而泛型接口的枚举类型是安全的,它返回实际类型的引用

四、迭代器

  有米有觉得创建枚举器和可枚举类型有点子复杂?C# 2.0 开始提供了更简单的创建方式,实际上编译器会为我们创建它们,它J就是迭代器(iterator),先看代码,它实现了一个产生和返回枚举器的迭代器

public IEnumerator<string> Colors()
{
string[] theColors = { "black", "white", "gray" };
for (int i = ; i < theColors.Length; i++)
yield return theColors[i];
}

  是不是很奇怪,yield return是what鬼,并且如果yield return在第一次迭代中返回,循环就永远不会获得其后续迭代了

  莫慌,慢慢来,通过迭代器块了解yield。迭代器块是有一个或多个yield语句的代码块,它可以是方法主体、访问器主体或运算符主体中的任意一种。和普通代码块不同,它描述了希望编译器为我们创建枚举器类的行为,包含两个特殊语句

  1. yield  return  指定了序列中返回的下一项

  2. yield  break  指定在序列中没有其他项  

下面是通过迭代器创建可枚举类型的例子

using System;
using System.Collections;
using System.Collections.Generic; namespace 枚举器
{
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
foreach(string str in mc)
{
Console.Write("{0} ",str);
}
Console.ReadKey();
}
} class MyClass
{
public IEnumerator<string> GetEnumerator()
{
IEnumerable<string> MyColor = Colors();
return MyColor.GetEnumerator();
} public IEnumerable<string> Colors()
{
string[] theColors = { "black", "white", "gray" };
for (int i = ; i < theColors.Length; i++)
yield return theColors[i];
}
}
}

结果为:  black  white  gray

五、产生多个可枚举类型

using System;
using System.Collections;
using System.Collections.Generic; namespace 枚举器
{
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
foreach(string str in mc.Colors())
{
Console.WriteLine("{0}",str);
} foreach(string str in mc.Colors2())
{
Console.WriteLine("{0}", str);
}
Console.ReadKey();
}
} class MyClass
{
public IEnumerable<string> Colors() //顺序输出
{
string[] theColors = { "black", "white", "gray" };
for (int i = ; i < theColors.Length; i++)
yield return theColors[i];
} public IEnumerable<string> Colors2() //逆序输出
{
string[] theColors = { "black", "white", "gray" };
for (int i=theColors.Length - ; i >=; i--)
yield return theColors[i];
}
}
}

六、迭代器作为属性输出

  和前面的代码非常类似,将前面的color函数改了

using System;
using System.Collections;
using System.Collections.Generic; namespace 枚举器
{
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
foreach (string str in mc.Colors1)
{
Console.Write("{0} ", str);
}
Console.WriteLine();
foreach (string str in mc.Colors2)
{
Console.Write("{0} ", str);
}
Console.ReadKey();
}
} class MyClass
{
public IEnumerable<string> Colors1
{
get
{
string[] theColors = { "black", "white", "gray" };
for (int i = ; i < theColors.Length; i++)
yield return theColors[i];
}
} public IEnumerable<string> Colors2
{
get
{
string[] theColors = { "black", "white", "gray" };
for (int i = theColors.Length - ; i >= ; i--)
yield return theColors[i];
}
}
}
}

      

C# 枚举器和迭代器的更多相关文章

  1. C#图解教程 第十八章 枚举器和迭代器

    枚举器和迭代器 枚举器和可枚举类型 foreach语句 IEnumerator接口 使用IEnumerable和IEnumerator的示例 泛型枚举接口迭代器 迭代器块使用迭代器来创建枚举器使用迭代 ...

  2. 设计模式 - 适配器模式(adapter pattern) 枚举器和迭代器 具体解释

    适配器模式(adapter pattern) 枚举器和迭代器 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考适配器模式(adapter patter ...

  3. C#-14 枚举器和迭代器

    一 枚举器和可枚举类型 当我们为数组使用foreach语句时,这个语句为我们依次取出了数组中的每一个元素. var arrInt = new int[] { 11, 12, 13, 14 }; for ...

  4. C#知识点-枚举器和迭代器

    一.几个基本概念的理解 问题一:为什么数组可以使用foreach输出各元素 答:数组是可枚举类型,它实现了一个枚举器(enumerator)对象:枚举器知道各元素的次序并跟踪它们的位置,然后返回请求的 ...

  5. 【Unity|C#】基础篇(20)——枚举器与迭代器(IEnumerable/IEnumerator)

    [学习资料] <C#图解教程>(第18章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...

  6. C#枚举器/迭代器

    一.枚举器 1.为什么foreach可以顺序遍历数组? 因为foreach可以识别可枚举类型,通过访问数组提供的枚举器对象来识别数组中元素的位置从而获取元素的值并打印出来. 2.什么是枚举器?可枚举类 ...

  7. C#中的枚举器(转)

    术语表 Iterator:枚举器(迭代器) 如果你正在创建一个表现和行为都类似于集合的类,允许类的用户使用foreach语句对集合中的成员进行枚举将会是很方便的.这在C# 2.0中比 C# 1.1更容 ...

  8. ruby迭代器枚举器

    迭代器一个迭代器是一个方法,这个方法里面有yield语句,使用了yield的方法叫做迭代器,迭代器并非一定要迭代,与传递给这个方法的块进行数据传输 yield将数据传给代码快,代码块再把数据传输给yi ...

  9. ruby中迭代器枚举器的理解

    参考<ruby编程语言>5.3迭代器和可枚举对象 迭代器一个迭代器是一个方法,这个方法里面有yield语句,这个方法里的yield语句,与传递给这个方法的块进行数据传输 yield将数据传 ...

随机推荐

  1. node-lessons

    教程:https://github.com/alsotang/node-lessons 0 nvm 的全称是 Node Version Manager,之所以需要这个工具,是因为 Node.js 的各 ...

  2. JBoss 系列四十九:JBoss 7/WildFly 中端口使用列表

    JBoss 7中端口使用列表 JBoss 7中所有配置都在一个文件中(standaone*.xml, domain.xml),和之前的JBoss相比JBoss 7用到的端口变少,我们将以表格的形式列出 ...

  3. RNN以及LSTM的介绍和公式梳理

    前言 好久没用正儿八经地写博客了,csdn居然也有了markdown的编辑器了,最近花了不少时间看RNN以及LSTM的论文,在组内『夜校』分享过了,再在这里总结一下发出来吧,按照我讲解的思路,理解RN ...

  4. 常用Java集合类总结

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 7.1.List(允许重复元素) ArrayList: 底层数据结构:Object[] 在查询(get).遍 ...

  5. HashSet源码解析

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 6.1.对于HashSet需要掌握以下几点 HashSet的创建:HashSet() 往HashSet中添加 ...

  6. ArrayBlockingQueue源码解析(1)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 注意:在阅读本文之前或在阅读的过程中,需要用到ReentrantLock,内容见<第五章 Reentr ...

  7. 为ElasticSearch添加HTTP基本认证

    ES的HTTP连接没有提供任何的权限控制措施,一旦部署在公共网络就容易有数据泄露的风险,尤其是加上类似elasticsearch-head这样友好的前端界面,简直让你的数据瞬间裸奔在黑客的眼皮底下.项 ...

  8. js的相关函数封装(正则表达式,获取url参数,时间格式化)

    一:// 验证中文名称 function isChinaName(name) { var pattern = /^[\u4E00-\u9FA5]{1,6}$/ return pattern.test( ...

  9. 谈一谈对MySQL InnoDB的认识及数据库事物处理的隔离级别

    介绍: InnoDB引擎是MySQL数据库的一个重要的存储引擎,和其他存储引擎相比,InnoDB引擎的优点是支持兼容ACID的事务(类似于PostgreSQL),以及参数完整性(有外键)等.现在Inn ...

  10. [LeetCode]640解方程式

    问题描述: 示例 1: 输入: "x+5-3+x=6+x-2" 输出: "x=2" 示例 2: 输入: "x=x" 输出: "In ...