C# IEnumerable 和 IEnumerator接口浅析
温故而知新,可以为师矣,有空经常复习一下基础知识是有必要的,并且能加深理解和记忆。
Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行遍历,IEnumerable和IEnumerator接口我有时候也有点迷糊,按官方的解释,IEnumerable是枚举器接口,IEnumerator是迭代器接口,从字面意思来看相差不大,逐一分析一下。
IEnumerable接口
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
继承IEnumerable接口的类需实现暴露出来的GetEnumerator()方法,并返回一个IEnumerator接口对象,看来真正做事的是IEnumerator,F12看一下IEnumerator又有什么鬼东西。
IEnumerator接口
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
IEnumerator接口有三个东东,一个属性Current,返回当前集合中的元素,方法MoveNext()移动到下一个,遍历不都是向后遍历的嘛,Reset(),字面意思重置,这个容易理解。做个假设:既然IEnumerable接口返回是IEnumerator接口迭代器来实现的,那么仅继承IEnumerator迭代器接口能不能实现一个自定义容器?
定义一个Phone类
public class Phone
{
public string Name;
public Phone(string name)
{
this.Name = name;
}
}
定义一个名为MyEnumerator迭代器,并现实它接口IEnumerator
public class MyEnumerator : IEnumerator
{
Phone[] p;
int idx = -;
public MyEnumerator(Phone[] t)
{
p = t;
}
public object Current
{
get
{
if (idx == -)
return new IndexOutOfRangeException();
return p[idx];
}
} public bool MoveNext()
{
idx++;
return p.Length > idx;
} public void Reset()
{
idx = -;
}
}
class Program
{
static void Main(string[] args)
{
show("-----------IEnumerator------------");
Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
MyEnumerator enumerator = new MyEnumerator(phones);
while (enumerator.MoveNext())
{
Phone p = enumerator.Current as Phone;
show(p.Name);
}
Console.ReadKey();
}
static void show(string i)
{
Console.WriteLine(i);
}
}
结果显示:

果然不出所料,真正做事情的是IEnumerator接口,即可循环访问自定义的一个容器,不过,初衷是想用Foreach来做循环访问、遍历的。那好,那就只能显示IEnumerable接口来做。稍稍改造一下Phone类:
public class Phone : IEnumerable
{
public string Name ;
public Phone(string name)
{
this.Name = name;
} Phone[] p;
public Phone(Phone[] t)
{
p = t;
}
public IEnumerator GetEnumerator()
{
return new MyEnumerator(p);
}
}
static void Main(string[] args)
{
show("-----------IEnumerator------------");
Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
MyEnumerator enumerator = new MyEnumerator(phones);
while (enumerator.MoveNext())
{
Phone p = enumerator.Current as Phone;
show(p.Name);
} show("-----------IEnumerable------------");
Phone phoneList = new Phone(phones);
foreach (Phone p in phoneList)
{
show(p.Name);
} Console.ReadKey();
}
结果显示:

大功告成,再扩展成通用的容器PhonePackage,继承泛型IEnumerable<T>接口即可。
public class PhonePackage<T> : IEnumerable<T>
{
private List<T> dataList = null; public void Add(T t)
{
if (dataList == null)
dataList = new List<T>();
dataList.Add(t);
} public IEnumerator<T> GetEnumerator()
{
foreach (T t in dataList)
{
yield return t;
}
} IEnumerator IEnumerable.GetEnumerator()
{
foreach (T t in dataList)
{
yield return t;
}
}
}
static void Main(string[] args)
{
show("-----------IEnumerator------------");
Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
MyEnumerator enumerator = new MyEnumerator(phones);
while (enumerator.MoveNext())
{
Phone p = enumerator.Current as Phone;
show(p.Name);
} show("-----------IEnumerable------------");
Phone phoneList = new Phone(phones);
foreach (Phone p in phoneList)
{
show(p.Name);
}
show("-----------IEnumerable<T>------------");
PhonePackage<Phone> phonePackage = new PhonePackage<Phone>();
phonePackage.Add(new Phone("iPhone 7s"));
phonePackage.Add(new Phone("iPhone 6s"));
phonePackage.Add(new Phone("iPhone 5s"));
foreach (Phone p in phonePackage)
{
show(p.Name);
}
Console.ReadKey();
}
static void show(string i)
{
Console.WriteLine(i);
}
结果显示:

IEnumerator迭代器接口挺啰嗦的,yield是简化了遍历的语法糖而已。
参考List<T>源码:http://www.projky.com/dotnet/4.5.1/System/Collections/Generic/List.cs.html
C# IEnumerable 和 IEnumerator接口浅析的更多相关文章
- 细说 C# 中的 IEnumerable和IEnumerator接口
我们先思考几个问题: 为什么在foreach中不能修改item的值? 要实现foreach需要满足什么条件? 为什么Linq to Object中要返回IEnumerable? 接下来,先开始我们的正 ...
- IEnumerable和IEnumerator接口
我们先思考几个问题:1.为什么在foreach中不能修改item的值?(IEnumerator的Current为只读)2.要实现foreach需要满足什么条件?(实现IEnumerator接口来实现的 ...
- IEnumerable、IEnumerator接口(如何增加迭代器功能)
IEnumerable.IEnumerator接口封装了迭代器功能,有了它,我们不需要将内部集合暴露出去,外界只需要访问我的迭代器接口方法即可遍历数据. 在C#中,使用foreach语句来遍历集合.f ...
- 迭代器学习之一:使用IEnumerable和IEnumerator接口
写博客是检验我学习的成果之一以及自我总结的一种方式,以后会经常利用这种方式进行技术交流和自我总结,其中认识不深难免会有错误,但是一直懂得不懂就问,不懂就学的道理! 1.首先看一个简单的列子 , , , ...
- C#基础知识系列九(对IEnumerable和IEnumerator接口的糊涂认识)
前言 IEnumerable.IEnumerator到现在为止对这两个接口还是不太理解,不理解但是自己总是想着试着要搞明白,毕竟自己用的少,所以在此先记录一下.以备自己日后可以来翻查,同时也希望园子里 ...
- C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield
IEnumerable / IEnumerator 首先,IEnumerable / IEnumerator 接口定义如下: public interface IEnumerable /// 可枚举接 ...
- IEnumerable和IEnumerator
概述 IEnumerable和IEnumerator接口存在的意义:用来实现迭代的功能! public interface IEnumerable { IEnumerator GetEnumerato ...
- IEnumerable和IEnumerator 详解 (转)
原文链接:http://blog.csdn.net/byondocean/article/details/6871881 参考链接:http://www.cnblogs.com/hsapphire/a ...
- [转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable
1.首先看一个简单的例子 int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Re ...
随机推荐
- hadoop初学
Hadoop: 官网(hadoop.apache.org)的定义: 一:Hadoop Common: 为Hadoop其它模块提供通用的支持 二:HDFS: 是Hadoop的分布式文件系统,其特点是高度 ...
- Linux下绝对经典的命令
1.使用远程终端时,可以使用如下命令: screen tmux 2.下载文件可以使用如下命令: curl wget 3.压缩解压缩可以使用: tar .zip.rar 4.使用抓包工具 tcpdump ...
- dedecms织梦判断当前页面是首页、栏目页还是文章页
根据全局变量$GLOBALS['_sys_globals']['curfile']的值来判断. 首页parview:列表页listview:文章页archives 应用示例: {dede:php}if ...
- EF数据迁移,未将对象引用设置到对象实例
现象: 执行Enable-Migrations -force时就报"未将对象引用设置到对象实例"的异常: DbProviderServicesExtensions.GetProvi ...
- iOS 添加WKWebView导致控制器无法释放的问题
在WkWebView与JavaScript交互中,经常会在原生中注入MessageHandler,app中注入MessageHandler的方法 WKWebViewConfiguration *con ...
- struts 中的创建Action的三种方法
1.对于直接创建类,不实现接口和继承任何的类 例如创建一个helloAction package cn.lonecloud.control; import com.opensymphony.xwork ...
- C编程之 一个容易忽视但是十分严重的小错误
while(...) { ...if(a=b) continue; } 调试时就一直执行continue.一直找不到原因,后面才发现是少一个"=": 还有一次就是也是在if中,if ...
- 《android开发艺术探索》读书笔记(十)--Android的消息机制
接上篇<android开发艺术探索>读书笔记(九)--四大组件 No1: 消息队列MessageQueue的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表,因为单链表 ...
- hihoCoder 1288 Font Size 二分
题意:给定一个宽度为和高度为的屏幕,如果字体的大小为,那么一行可以显示个字,每一页可以显示行.给出段文本段落,每段有个文字,问现在能设置的最大字体并且总的页数不能超过? 思路:如果知道字体大小很容易求 ...
- SIFT解析(二)特征点位置确定
最近微博上有人发起投票那篇论文是自己最受益匪浅的论文,不少人说是lowe的这篇介绍SIFT的论文.确实,在图像特征识别领域,SIFT的出现是具有重大意义的,SIFT特征以其稳定的存在,较高的区分度推进 ...