C#的枚举数(Enumerator)和可枚举类型(Enumerable)
数组可以被foreach语句遍历数组中的元素,原因是数组可以按需提供一个叫做枚举数(enumerator)的对象.枚举数可以依次返回请求的数组的元素.
对于有枚举数的类型而言,必须有一个方法来获取它们.在.NET中获取一个对象枚举数的标准用法是调用对象的GetEnumerator方法.实现GetEnumerator方法的类型叫做可枚举类型(enumerable),数组就是可枚举类型.
要注意枚举数(enumerator)和可枚举类型(enumerable)的区别和联系.
枚举数是可以依次返回集合项的类对象,可枚举类型是带有GetEnumerator方法的类型,它返回枚举数.
当foreach被用来遍历可枚举类型时,它就会执行如下的行为:
1,通过调用GetEnumerator方法获取对象的枚举数.
2,从枚举数中请求每一项并且把它作为迭代变量,代码可以读但不可以改变.
枚举数共有3种,可以用以下方式来实现枚举数:
1 IEnumerator/IEnumerable接口 ,叫做非泛型接口形式.
2 IEnumerator<T>/IEnumerable<T>接口, 叫做泛型接口形式.
3 不使用接口形式.
IEnumerator接口
IEnumerator接口包含3个函数成员:Current,MoveNext,Reset
Current返回序列中当前项的属性,它是一个只读属性.返回object类型的引用,所以可以返回任何类型.
MoveNext是把枚举数位置前进到集合的下一项的方法,它返回布尔值,指示新位置是有效位置还是已经超过了序列的尾部.如果是已经到达了尾部,则返回false.
Reset方法把位置重置为原始状态.
查看下面的代码:
int[] MyArray = { 10, 11, 12, 13 }; //创建数组
IEnumerator ie = MyArray.GetEnumerator(); //获取枚举数
while (ie.MoveNext()) //移到下一项
Console.WriteLine((int)ie.Current); //获取当前项并输入
枚举数的初始位置是-1,所以要想获取第一个元素就必须执行MoveNext()方法.
上面的代码就是调用枚举数的Current和MoveNext成员函数手工地遍历数组中的元素.
或者可以直接使用foreach直接获取:
foreach(int i in MyArray)
Console.WriteLine(i);
下面列出一个颜色名数组的枚举数类:
using System.Collections;
class ColorEnumerator : IEnumerator
{
private string[] Colors;
private int Position = -1;
public object Current
{
get
{
if (Position == -1)
throw new InvalidOperationException();
if (Position == Colors.Length)
throw new InvalidOperationException(); ;
return Colors[Position];
}
}
public bool MoveNext()
{
if (Position < Colors.Length - 1)
{
Position ++;
return true;
}
else
return false;
}
public void Reset()
{
Position = -1;
}
public ColorEnumerator(string[] theColors) //构造函数
{
Colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length - 1; i++)
Colors[i] = theColors[i];
}
}
以上代码就构造了一个完整的枚举数类型.下面生成对象返回枚举数.
class Program
{
static void Main()
{
ColorEnumerator ce = new ColorEnumerator(new string[]{"yellow","red","white","black"});
while (ce.MoveNext())
Console.WriteLine((string)(ce.Current));
Console.ReadKey();
}
}
如果要用foreach来遍历枚举数,需要再定义一个可枚举类型的类,这个类要实现IEnumerable接口的功能.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
class MyEnumerable : IEnumerable //定义一个可枚举类型的类
{
string[] MyColor = new string[] { "yellow", "red", "black", "white" };
public IEnumerator GetEnumerator() //实现接口
{
return new ColorEnumerator(MyColor); //返回一个枚举数的对象
}
}
现在就可以使用foreach来遍历可枚举类型对象的所有元素了.
class Program
{
static void Main()
{
MyEnumerable me = new MyEnumerable();
foreach (string i in me)
Console.WriteLine(i);
Console.ReadKey();
}
}
总结一下,如果想遍历一个对象中的所有元素,可以把对象设为枚举数类型(实现IEnumerator接口)和可枚举的类类型(实现IEnumerable接口),前者需要实现IEnumerator接口的Current,MoveNext和Rest成员函数,后者需要实现IEnumerable接口的GetEnumerator成员函数,由于GetEnumerator返回的是IEnumerator对象,所以还要建立一个派生于IEnumerator的枚举数类,在这个类中实现Current,MoveNext和Reset成员函数.派生于IEnumerable的类可以使用foreach代码来遍历对象中的全部元素.
摘自:syexy的博客
C#的枚举数(Enumerator)和可枚举类型(Enumerable)的更多相关文章
- C#枚举数和迭代器
大道至简,始终认为简洁是一门优秀的编程语言的一个必要条件.相对来说,C#是比较简洁的,也越来越简洁.在C#中,一个关键字或者语法糖在编译器层面为我们做了很多乏味的工作,可能实现的是一个设计模式,甚至是 ...
- 【C#】IEnumrator的枚举数和IEnumerable接口
声明IEnumerator的枚举数 要创建非泛型接口的枚举数,必须声明实现IEnumerator接口的类,IEnumerator接口有如下特性: 1.她是System.Collections命名空间的 ...
- 实现自定义集合的可枚举类型(IEnumerable)和枚举数(IEnumerator )
下面的代码示例演示如何实现自定义集合的 IEnumerable 和 IEnumerator 接口: using System; using System.Collections; using Syst ...
- java枚举与.net中的枚举区别
通过一段时间的项目实践,发现java中的枚举与.net中的枚举有很大的差别,初期造成了我对java中的枚举一些错误理解及部分有缺陷的应用,其实追其原因还是因为我会习惯性的认为java的枚举在作用以及定 ...
- C# 给枚举定义DescriptionAttribute,把枚举转换为键值对
在C#中,枚举用来定状态值很方便,例如我定义一个叫做Season的枚举 public enum Season { Spring = 1, Summer = 2, Autumn = 3, Winter ...
- 【C/C++开发】C++之enum枚举量声明、定义、使用与枚举类详解与枚举类前置类型声明
众所周知,C/C++语言可以使用#define和const创建符号常量,而使用enum工具不仅能够创建符号常量,还能定义新的数据类型,但是必须按照一定的规则进行,下面我们一起看下enum的使用方法. ...
- Swift 枚举-从汇编角度看枚举内存结构
一.基本使用 先看枚举的几种使用(暂不要问,看看是否都能看懂,待会会逐一讲解) 1.操作一 简单使用 //第一种方式 enum Direction { case east case west case ...
- 暴力枚举-数长方形(hdu5258)
数长方形 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- Swift----函数 、 闭包 、 枚举 、 类和结构体 、 属性
1 数组排序 1.1 问题 本案例实现一个整型数组排序的函数,数组排序的规则由传递的规则函数决定. 1.2 方案 首先定义一个整型数组排序函数sortInts,该函数有一个整型数组类型的参数,该参数必 ...
随机推荐
- 手动配置gradle
最近从github倒入项目,运行的特别慢gradle配置有问题,解决方法: 1.C:\android\demo\hellocharts-android-master\gradle\wrapper 目录 ...
- UVA 11396 Claw Decomposition(二分图)
以“爪”形为单元,问所给出的无向图中能否被完全分割成一个个单元. 分析图的性质,由于已知每个点的度是3,所以“爪”之间是相互交错的,即把一个“爪”分为中心点和边缘点,中心点被完全占据,而边缘点被三个“ ...
- php yii多表查询
一个Company记录可以对应多个CompanyUser纪录Company表: [['id', 'nature_id', 'scale_id', 'pro_id', 'created_at', 'up ...
- Java [Leetcode 223]Rectangle Area
题目描述: Find the total area covered by two rectilinear rectangles in a 2D plane. Each rectangle is def ...
- 最简单的视音频播放示例3:Direct3D播放YUV,RGB(通过Surface)
上一篇文章记录了GDI播放视频的技术.打算接下来写两篇文章记录Direct3D(简称D3D)播放视频的技术.Direct3D应该Windows下最常用的播放视频的技术.实际上视频播放只是Direct3 ...
- 在linux的shell里访问一个URL
在linux上访问一个网址有四种方法 1.elinks,用法举例: [weishusheng@centOS6 ~]$ elinks -dump http://www.baidu.com 2. wget ...
- Oracle 课程三之表设计
完成本课程的学习后,您应该能够: •普通堆表优点和缺点 •理解rowid •全局临时表优点.缺点和适用场景 •分区表的类型和原理.优点和缺点.适用场景 •表字段的高效设计 •sequence的设计 ...
- linux下利用backtrace追踪函数调用堆栈以及定位段错误
一般察看函数运行时堆栈的方法是使用GDB(bt命令)之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的. 在glibc ...
- hdu 1198 Farm Irrigation
令人蛋疼的并查集…… 我居然做了大量的枚举,居然过了,我越来越佩服自己了 这个题有些像一个叫做“水管工”的游戏.给你一个m*n的图,每个单位可以有11种选择,然后相邻两个图只有都和对方连接,才判断他们 ...
- JVM 性能调优实战之:使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码
本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 提升到 20 (提升了 7 倍) ...