http://www.cnblogs.com/edison1105/archive/2012/07/30/2616082.html

1、首先看一个简单的例子

int[] myArray = { 1, 32, 43, 343 };
IEnumerator myie = myArray.GetEnumerator();
myie.Reset();
while (myie.MoveNext())
{
int i = (int)myie.Current;
Console.WriteLine("Value: {0}", i);
}
相信很多人都不会像上面这样去遍历myArray这个数组,通常我们这样会这样做
            foreach (int item in myArray)
Console.WriteLine(item.ToString());

在大部分的情况下,很多人会使用for和foreach来遍历数组,而对于上面的语法却用的很少,但是对foreach的具体来历还很模糊!


2、理解foreach

大家都知道要实现foreach的必须要实现IEnumerable和IEnumerator的接口,只有实现了它们,才能实现遍历,所以要讲foreach的来历,必须要把那两个接口给搞清楚点!

这边也想说明一点的是:如果对这两个接口有了一定的了解后,只要实现那个GetEnumerator方法即可,而不需要实现于IEnumerable接口,这只是针对对这两个接口有一定了解的朋友!

2.1 IEnumerable

具体的作用:就是使实现这个接口的对象成为可枚举类型。

IEnumerable接口包含一个GetEnumerator方法,返回值为IEnumerator的类型!代码如下:

    public class MyColors : IEnumerable
{
string[] colors = { "Red", "Yellow", "Biue" };
public IEnumerator GetEnumerator()
{
return colors.GetEnumerator();
}
}

那么我们在客户端进行调用的时候就可以这样做了!

            MyColors colors = new MyColors();
foreach (string item in colors)
Console.WriteLine(item);
这样就能使用实现这个接口的对象进行foreach遍历了,就是这么简单的一个列子,这边可能有的人会有疑问,我们就实现了IEnumerable接口但却没实现IEnumerator接口,可是我们不是说只有实现了这两个接口才可以进行foreach遍历吗?可以这样说当使用forach进行遍历的时候,编译器会到这个对象的类中去寻找GetEnumerator方法,找到这个方法后返回这个一个IEnumerator的对象(枚举数),而我这边返回的是“colors.GetEnumerator()”,是一个数组对象调用它本身中的“GetEnumerator”方法,所以说数组本身就实现了IEnumerator接口,那么两个接口都实现了,不就好实现foreach遍历了,其实在实现遍历枚举数的时候编译器会自动去调用数组中实现枚举数的类中的方法。

2.2  IEnumerator

接口的作用:实现可枚举数,首先看一下接口的定义:

包含一个属性两个方法

MoveNext → 把当前的项移动到下一项(类似于索引值),返回一个bool值,这个bool值用来检查当前项是否超出了枚举数的范围!

Current → 获取当前项的值,返回一个object的类型(这边会涉及到装箱和拆箱的问题 → 后面讲泛型的时候会涉及到)!

Reset → 顾名思义也就是把一些值恢复为默认值,比如把当前项恢复到默认状态值!

    public class MyIEnumerator : IEnumerator
{
public MyIEnumerator(string[] colors)
{
this.colors = new string[colors.Length];
for (int i = 0; i < this.colors.Length; i++)
this.colors[i] = colors[i];
} string[] colors;    //定义一个数组,用来存储数据 int position = -1;    //定义当前项的默认值,也就是索引值,一开始认识数组的索引从“0”开始,
//怎么默认设置他为“-1”呢,最后才想明白,这样设置是合情合理的! public object Current //根据当前项获取相应的值
{
get
{
return colors[position];   //返回当前项的值,但是会做一个装箱的操作!
}
} public bool MoveNext()      //移动到下一项
{
if (position < colors.Length - 1)    //这就是设置默认值为-1的根据
{
position++;
return true;
}
else
{
return false;
}
} //重置当前项的值,恢复为默认值
public void Reset()
{
this.position = -1;
}
}

上面讲到的IEnumerable接口中GetEnumerator方法是获取要遍历的枚举数,在我们没有创建自己的遍历枚举数的类时,我们使用的是Array的遍历枚举数的方法(关于数组的可枚举类型和枚举数会在下一篇讲到),但这个有的时候不一定适合我们,我们需要为自己定制一个更合适的,所以我们要创建自己的枚举数类(也就是上面的代码),把第三点和第四点的代码合并起来(改动一点代码),如下:

        public class MyColors   //: IEnumerable
{
string[] colors = { "Red", "Yellow", "Biue" }; public IEnumerator GetEnumerator()
{
return new MyIEnumerator(colors);
}
}

3、关于可枚举类型和枚举数

①可枚举类型 → 实现IEnumerable接口,可以不需要直接实现这个接口,但必须有个GetEnumerator方法,返回值类型必须为IEnumerator类型,也就是第四点最后一段代码中接口注释的那种写法!

②枚举数 → 实现IEnumerator接口,实现全部方法,首先是调用GetEnumerator返回一个类型为IEnumerator的枚举数,然后编译器会隐式的调用实现IEnumerator类中的方法和属性!

总结:所以实现foreach遍历,必须达到上面的两种条件才能进行遍历对象,他们可以写在一起也可以分开,最好是分开,进行职责分离,一个类干一件事总归是好事!也满足面向对象的单一指责设计原则。

下面的代码示例演示如何实现自定义集合的 IEnumerable 和 IEnumerator 接口(代码来自MSDN)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApplication1
{
public class Person
{
public Person(string fName, string lName)
{
this.firstName = fName;
this.lastName = lName;
} public string firstName;
public string lastName;
} public class People : IEnumerable
{
private Person[] _people;
public People(Person[] pArray)
{
_people = new Person[pArray.Length]; for (int i = 0; i < pArray.Length; i++)
{
_people[i] = pArray[i];
}
} IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
} public PeopleEnum GetEnumerator()
{
return new PeopleEnum(_people);
}
} public class PeopleEnum : IEnumerator
{
public Person[] _people; // Enumerators are positioned before the first element
// until the first MoveNext() call.
int position = -1; public PeopleEnum(Person[] list)
{
_people = list;
} public bool MoveNext()
{
position++;
return (position < _people.Length);
} public void Reset()
{
position = -1;
} object IEnumerator.Current
{
get
{
return Current;
}
} public Person Current
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
} class Program
{
static void Main(string[] args)
{
Person[] peopleArray = new Person[3]
{
new Person("John", "Smith"),
new Person("Jim", "Johnson"),
new Person("Sue", "Rabon"),
}; People peopleList = new People(peopleArray);
foreach (Person p in peopleList)
Console.WriteLine(p.firstName + " " + p.lastName);
}
}
}

无图无真相

我并非标题党,下面介绍IList,ICollection,IQueryable

1、IList 是 ICollection 接口的子代,并且是所有非泛型列表的基接口。IList 实现有三种类别:只读、固定大小和可变大小。无法修改只读 IList。固定大小的 IList 不允许添加或移除元素,但允许修改现有元素。可变大小的 IList 允许添加、移除和修改元素。

2、ICollection 接口是 System.Collections 命名空间中类的基接口。ICollection 接口扩展 IEnumerable;IDictionary 和 IList 则是扩展 ICollection 的更为专用的接口。 IDictionary 实现是键/值对的集合,如 Hashtable 类。 IList 实现是值的集合,其成员可通过索引访问,如 ArrayList 类。  某些集合(如 Queue 类和 Stack 类)限制对其元素的访问,它们直接实现 ICollection 接口。  如果 IDictionary 接口和 IList 接口都不能满足所需集合的要求,则从 ICollection 接口派生新集合类以提高灵活性。定义所有非泛型集合的大小、枚举器和同步方法。

3、IQueryable 提供对未指定数据类型的特定数据源的查询进行计算的功能,IQueryable 接口由查询提供程序实现。 该接口只能由同时实现 IQueryable(Of T) 的提供程序实现。 如果该提供程序不实现 IQueryable(Of T),则无法对提供程序数据源使用标准查询运算符。 IQueryable 接口继承 IEnumerable 接口,以便在前者表示一个查询时可以枚举该查询的结果。 枚举强制执行与 IQueryable 对象关联的表达式树。 “执行表达式树”的定义是查询提供程序所特有的。 例如,它可能涉及将表达式树转换为适用于基础数据源的查询语言。 在调用 Execute 方法时将执行不返回可枚举结果的查询。

不好意思,这里就先粗略的介绍一下了,都说我很懒了,明天还要上班,下次再续…

IList,ICollection,IEnumerable,IEnumerator,IQueryable的更多相关文章

  1. C#编程之IList<T>、List<T>、ArrayList、IList, ICollection、IEnumerable、IEnumerator、IQueryable 和 IEnumerable的区别

    额...今天看了半天Ilist<T>和List<T>的区别,然后惊奇的发现使用IList<T>还是List<T>对我的项目来说没有区别...  在C#中 ...

  2. C#中的 IList, ICollection ,IEnumerable 和 IEnumerator

    IList, ICollection ,IEnumerable 很显然,这些都是集合接口的定义,先看看定义: // 摘要: // 表示可按照索引单独访问的对象的非泛型集合. [ComVisible(t ...

  3. IList, ICollection ,IEnumerable AND IEnumerator in C#

    IList, ICollection ,IEnumerable 很显然,这些都是集合接口的定义,先看看定义: // 摘要: // 表示可按照索引单独访问的对象的非泛型集合. [ComVisible(t ...

  4. IEnumerable、IEnumerator、ICollection、IList、List的继承关系及简单使用

    IEnumerable和IEnumerable<T>接口在.NET中是非常重要的接口,它允许开发人员定义foreach语句功能的实现并支持非泛型方法的简单的迭代,IEnumerable和I ...

  5. 【5min+】你怎么穿着品如的衣服?IEnumerable AND IEnumerator

    系列介绍 简介 [五分钟的dotnet]是一个利用您的碎片化时间来学习和丰富.net知识的博文系列.它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的. ...

  6. IEnumerable和IEnumerator 详解 (转)

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

  7. IEnumerable和IEnumerator 详解

    初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下 ...

  8. IEnumerable和IEnumerator 详解 【转】

    初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下 ...

  9. 转载 IEnumerable和IEnumerator 详解

    初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下 ...

  10. IEnumerable和IEnumerator 详解 分类: C# 2014-12-05 11:47 18人阅读 评论(0) 收藏

    原:<div class="article_title"> <span class="ico ico_type_Original">&l ...

随机推荐

  1. 解决:百度编辑器UEditor,怎么将图片保存到图片服务器,或者上传到ftp服务器的问题(如果你正在用UE,这篇文章值得你看下)

    在使用百度编辑器ueditor的时候,怎么将图片保存到另一个服务器,或者上传到ftp服务器?这个问题,估计很多使用UE的人会遇到.而且我百度过,没有找到这个问题的解决方案.那么:本篇文章就很适合你了. ...

  2. NetCore偶尔有用篇:NetCore项目添加MIME

    一.简介 1.系统默认给我们提供的一些文件类型的处理方式. 2.系统没有为我们提供处理的文件类型无法使用,例如:apk 3.这里候就需要自己添加MIME,才能进行访问 4.下面就是添加apk访问的示例 ...

  3. ueditor图片上传插件的使用

    在项目里使用到ueditor图片上传插件,以前图片上传都是直接使用js代码直接上传图片,比较麻烦,而且效率也比较低,而ueditor这款插件完美的解决了这个问题,这个是百度开发的一款富文本编辑器,在这 ...

  4. 11-使用EF操作数据库

    本篇博客对应视频讲解 回顾 上一篇教程我们讲了XML与JSON的序列化问题,我们可以看到序列化实际上也是不同形式的转换,我们通常要以字节流的形式做中转.同时我们也可以看到,对于序列化这种常见的需求,我 ...

  5. Dockerfile指令详解下

    VOLUME 定义匿名卷 VOLUME指令的格式为: VOLUME [,...] VOLUME 之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库 ...

  6. python pip安装模块提示错误failed to create process

    python pip安装模块提示错误failed to create process 原因: 报这个错误的原因,是因为python的目录名称或位置发生改动. 解决办法: 1.找到修改python所在的 ...

  7. C# 程序运行中的流程控制

    1.C#之流程控制语句:计算机程序执行的控制流程由三种基本的控制结构控制,即顺序结构,选择结构,循环结构. 1) 顺序结构:从上到下,按照书写顺序执行每一条语句,不会发生跳跃. 代码段1; // 先执 ...

  8. css之px自动转rem—sublime 插件CSSREM

    CSSREM CSSREM 是一个CSS的 px 值转 rem 值的Sublime Text3自动完成插件.先来看看插件的效果: 一个CSS的px值转rem值的Sublime Text 3自动完成插件 ...

  9. 漫谈NIO(3)之Netty实现

    1.前言 上一章结合Java的NIO例子,讲解了多路IO复用的一个基本使用方法,通过实际编码加深对其理解.本章开始进入Netty的环节,前面两章都是为了Netty进行铺垫说明.此节将对比Java的NI ...

  10. Linq基础知识之延迟执行

    Linq中的绝大多数查询运算符都有延迟执行的特性,查询并不是在查询创建的时候执行,而是在遍历的时候执行,也就是在enumerator的MoveNext()方法被调用的时候执行,大说数Linq查询操作实 ...