温故而知新,可以为师矣,有空经常复习一下基础知识是有必要的,并且能加深理解和记忆。

  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接口浅析的更多相关文章

  1. 细说 C# 中的 IEnumerable和IEnumerator接口

    我们先思考几个问题: 为什么在foreach中不能修改item的值? 要实现foreach需要满足什么条件? 为什么Linq to Object中要返回IEnumerable? 接下来,先开始我们的正 ...

  2. IEnumerable和IEnumerator接口

    我们先思考几个问题:1.为什么在foreach中不能修改item的值?(IEnumerator的Current为只读)2.要实现foreach需要满足什么条件?(实现IEnumerator接口来实现的 ...

  3. IEnumerable、IEnumerator接口(如何增加迭代器功能)

    IEnumerable.IEnumerator接口封装了迭代器功能,有了它,我们不需要将内部集合暴露出去,外界只需要访问我的迭代器接口方法即可遍历数据. 在C#中,使用foreach语句来遍历集合.f ...

  4. 迭代器学习之一:使用IEnumerable和IEnumerator接口

    写博客是检验我学习的成果之一以及自我总结的一种方式,以后会经常利用这种方式进行技术交流和自我总结,其中认识不深难免会有错误,但是一直懂得不懂就问,不懂就学的道理! 1.首先看一个简单的列子 , , , ...

  5. C#基础知识系列九(对IEnumerable和IEnumerator接口的糊涂认识)

    前言 IEnumerable.IEnumerator到现在为止对这两个接口还是不太理解,不理解但是自己总是想着试着要搞明白,毕竟自己用的少,所以在此先记录一下.以备自己日后可以来翻查,同时也希望园子里 ...

  6. C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield

    IEnumerable / IEnumerator 首先,IEnumerable / IEnumerator 接口定义如下: public interface IEnumerable /// 可枚举接 ...

  7. IEnumerable和IEnumerator

    概述 IEnumerable和IEnumerator接口存在的意义:用来实现迭代的功能! public interface IEnumerable { IEnumerator GetEnumerato ...

  8. IEnumerable和IEnumerator 详解 (转)

    原文链接:http://blog.csdn.net/byondocean/article/details/6871881 参考链接:http://www.cnblogs.com/hsapphire/a ...

  9. [转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable

    1.首先看一个简单的例子 int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Re ...

随机推荐

  1. 基于flash的web视频对讲直播测试

    由于项目的需求,要在web上实现视频通话的需求.现成的方案有WebRTC,基于浏览器的成熟方案,但是这个方案和公司项目需求有几个点冲突.后来考虑到基于flash的方案.参考雷神的博客 simplest ...

  2. vue2.0实现前端星星评分功能组件

    <template id="pingJia"> <div> <ul> <li :class="{li1:1,bg1:index% ...

  3. shared_ptr模版推导的问题

    问题描述 今天在帮同事解决问题时,发现了这个比较有意思的现象,特记录下来备忘. 问题是这样的,同事开发的是应用程序动态库模块,通过应用的框架中以接口方式供外部使用.然后他想对这些接口生命周期进行控制, ...

  4. 谈谈语音通信中的各种tone

    今天谈的这个主题(tone)存在于我们的日常打电话过程中.先举两个场景:1,你拿起固话话筒准备打电话,按电话号码前先从话筒里听到"嗡"的连续音,这叫dial tone(拨号音,表示 ...

  5. 应用负载均衡之LVS(三):使用ipvsadm以及详细分析VS/DR模式

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  6. 三、scrapy后续

    CrawlSpiders 通过下面的命令可以快速创建 CrawlSpider模板 的代码: scrapy genspider -t crawl tencent tencent.com 我们通过正则表达 ...

  7. CEF小白人系列2-DEV环境配置-Windows10+SDK+VS2015

    以下资料整理来自CEF官方教学.作者做了翻译和整理.并会以一种重事件操作的方式来一点点入门. 3个问题: 在上一篇内容中我们了解了什么是CEF,能干些什么.必要的物理学习环境. 下面我们也是以带着问题 ...

  8. php进阶之路--转载

    之前有看过相关的文章,觉得还是这篇详细点,有具体的目标实现起来才更有动力 转载自:http://wen.52fhy.com/2016/2016-09-03-PHP-cheng-xu-yuan-xue- ...

  9. mac清除某个端口的占用

    lsof -i:8080查找某个应用的pid kill  pid就可以了

  10. vue父子组件之间的通信

    利用props在子组件接受父组件传过来的值1.父组件parentComp.vue <template> <childComp :fromParentToChild="fro ...