概述

IEnumerable和IEnumerator接口存在的意义:用来实现迭代的功能!

    public interface IEnumerable
{
IEnumerator GetEnumerator();
} public interface IEnumerator
{
object Current { get; } bool MoveNext(); void Reset();
}

迭代的原理

首先来说一下集合实现的原理:对于ArrayList、List<T>等集合,类中有一个私有的数组类型字段,向集合中添加数据时调用Add方法(将数据元素添加到私有数组字段中),而调用类的其他方法时,其实就是对私有数组类型字段的操作。

 public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
//省略其他代码
private object[] _items; public virtual int Add(object value)
{
if (this._size == this._items.Length)
{
this.EnsureCapacity(this._size + );
}
this._items[this._size] = value;
this._version++;
return this._size++;
}
}

ArrayList

 public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
//省略其他代码
private T[] _items; public void Add(T item)
{
if (this._size == this._items.Length)
{
this.EnsureCapacity(this._size + );
}
this._items[this._size++] = item;
this._version++;
}
}

List

所以对于这些集合来说,本质上集合中的所有元素都是保存在一个私有数组类型的字段中,众所周知,对于ArrayList或者List<T>都可以使用foreach进行迭代,查看集合中的元素。

        static void Main(string[] args)
{
List<string> strs=new List<string>();
strs.Add("DD");
strs.Add("FF");
strs.Add("VV");
strs.Add("WW");
foreach (String str in strs)
{
Console.WriteLine(str);
}
Console.ReadKey();
}

上述这个foreach的迭代的过程是如何实现的呢?foreach为什么可以逐个遍历所以集合中的元素呢?下面我们就用IL反汇编程序来查看上述代码的foreach部分的IL!

  IL_0039:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
IL_003e: stloc.2
.try
{
IL_003f: br.s IL_0052
IL_0041: ldloca.s CS$5$0000
IL_0043: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current()
IL_0048: stloc.1
IL_0049: nop
IL_004a: ldloc.1
IL_004b: call void [mscorlib]System.Console::WriteLine(string)
IL_0050: nop
IL_0051: nop
IL_0052: ldloca.s CS$5$0000
IL_0054: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext()
IL_0059: stloc.3
IL_005a: ldloc.3
IL_005b: brtrue.s IL_0041
IL_005d: leave.s IL_006e
} // end .try
finally
{
IL_005f: ldloca.s CS$5$0000
IL_0061: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
IL_0067: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_006c: nop
IL_006d: endfinally
}

看不懂?没关系啦,那么我们就来大致的猜想一下,我们的foreach生成了这么一大坨的IL中居然有Enumerator什么的,难道跟这个有关系吗?恰巧听说IEnumerable和IEnumrator用来实现迭代,恰恰巧我们的ArrayList、List<T>集合都是实现了IEnumerable接口。那么我们就来做的大胆的假设,foreach其实就是执行跟IEnumerable和IEnumrator接口相关的代码,并对保存集合的私有数组字段的索引进行操作,从而来实现迭代的功能。

static void Main(string[] args)
{
List<string> strs=new List<string>();
strs.Add("DD");
strs.Add("FF");
strs.Add("VV");
strs.Add("WW");
IEnumerator<string> items = strs.GetEnumerator();
while (items.MoveNext())
{
Console.WriteLine(items.Current);
}
Console.ReadKey();
}

这段代码也同样实现了对集合元素迭代的功能!在来看一下这个迭代生成的相关IL。

  IL_0038:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
IL_003d: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
IL_0042: stloc.1
IL_0043: br.s IL_0053
IL_0045: nop
IL_0046: ldloc.1
IL_0047: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
IL_004c: call void [mscorlib]System.Console::WriteLine(string)
IL_0051: nop
IL_0052: nop
IL_0053: ldloc.1
IL_0054: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0059: stloc.2
IL_005a: ldloc.2
IL_005b: brtrue.s IL_0045

嘿嘿,对比两者生成的IL,目测他们的执行过程中调用的IL指令大体上是一致的(IL指令啥的暂时我也不是很了解),所以我们的猜想应该是正确的,foreach在本质上其实就是通过ArrayList、List<T>中定义的GetEnumerator方法,以及后续的代码实现的!下面就来看看List<T>中是如何定义的。

public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
private T[] _items;
public List<T>.Enumerator GetEnumerator()
{
return new List<T>.Enumerator(this);
}
public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator
{
private List<T> list;
private int index;
private int version;
private T current; public T Current
{ get
{
return this.current;
}
} object IEnumerator.Current
{ get
{
if (this.index == || this.index == this.list._size + )
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
}
return this.Current;
}
}
internal Enumerator(List<T> list)
{
this.list = list;
this.index = ;
this.version = list._version;
this.current = default(T);
} public void Dispose()
{
} public bool MoveNext()
{
List<T> list = this.list;
if (this.version == list._version && this.index < list._size)
{
this.current = list._items[this.index];
this.index++;
return true;
}
return this.MoveNextRare();
}
private bool MoveNextRare()
{
if (this.version != this.list._version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
this.index = this.list._size + ;
this.current = default(T);
return false;
} void IEnumerator.Reset()
{
if (this.version != this.list._version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
this.index = ;
this.current = default(T);
}
}
}

List<T>

哇哦,原来迭代器是这样的呀!!!!

自定义一个简单的支持迭代的集合

下面我们就来自定义一个支持迭代器的集合

public class UserDefinedCollection<T>:IEnumerable<T>
{
private List<T> list = new List<T>(); public UserDefinedCollection(List<T> param)
{
list = param;
}
public IEnumerator<T> GetEnumerator()
{
return new UserDefinedEnum<T>(list);
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
} private sealed class UserDefinedEnum<T>:IEnumerator<T>
{
private List<T> list = null;
private int _CurrentIndex;
private T _CurrentElement; public UserDefinedEnum(List<T> param)
{
this.list = param;
this._CurrentIndex = ;
_CurrentElement = default(T); } public T Current
{
get
{
return _CurrentElement;
}
} object IEnumerator.Current
{
get { return Current; }
} public bool MoveNext()
{
if (this._CurrentIndex < this.list.Count)
{
this._CurrentElement = this.list[this._CurrentIndex++];
return true;
}
return false;
} public void Reset()
{
this._CurrentElement = default(T);
this._CurrentIndex = ;
}
public void Dispose()
{ }
} }

测试自定义集合的迭代功能:

            List<string> strs=new List<string>();
strs.Add("DD");
strs.Add("FF");
strs.Add("VV");
strs.Add("WW");
UserDefinedCollection<String> user = new UserDefinedCollection<string>(strs);
IEnumerator<string> iEnumerator = user.GetEnumerator(); while (iEnumerator.MoveNext())
{
Console.WriteLine(iEnumerator.Current);
} foreach (String str in user)
{
Console.WriteLine(str);
}

扩展:由模型绑定中,绑定泛型类型时学习到泛型相关的知识!

//调用1
    ExtraGenericInterface(typeof(List<User>),typeof(IEnumerable<>))
    //调用2
    ExtraGenericInterface(typeof(IEnumerable<User>),typeof(IEnumerable<>))     public Type ExtraGenericInterface(Type queryType, Type interfaceType)
{
//当前类型queryType是否是泛型
bool b = queryType.IsGenericType;
//返回可以构造当前泛型类型的一个泛型类型,即:由IEnumerable<User>得到 IEnumerable<>
Type tt = queryType.GetGenericTypeDefinition(); bool ttt = tt == interfaceType ? true : false; Func<Type, bool> predicate = t => t.IsGenericType && (t.GetGenericTypeDefinition() == interfaceType);
//Func<Type, bool> predicate = delegate(Type queryType2){return false;};
//如果当前类型是泛型,并且该发行是由interfaceType类型构造的。
if (predicate(queryType))
{
return queryType;
}
else
{
//获取当前类实现的所有类和接口
Type[] types = queryType.GetInterfaces();
//在数组中找,并返回满足 predicate 条件的第一个元素
//也就是在所有父类或实现的接口中找到是泛型并且构造此泛型的类型是interfaceType类型的第一个元素
         //FirstOrDefault<Type>中Type是后面委托predicate的参数类型 
Type tttt = types.FirstOrDefault<Type>(predicate); return queryType.GetInterfaces().FirstOrDefault<Type>(predicate);
} }

  

IEnumerable和IEnumerator的更多相关文章

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

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

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

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

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

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

  4. 关于迭代器中IEnumerable与IEnumerator的区别

    首先是IEnumerable与IEnumerator的定义: 1.IEnumerable接口允许使用foreach循环,包含GetEnumerator()方法,可以迭代集合中的项. 2.IEnumer ...

  5. IEnumerable和IEnumerator 详解 (转)

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

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

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

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

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

  8. 转载IEnumerable与IEnumerator区别

    public interface IEnumerable {     IEnumerator GetEnumerator(); }   public interface IEnumerator {   ...

  9. IEnumerable、IEnumerator与yield的学习

    我们知道数组对象可以使用foreach迭代进行遍历,同时我们发现类ArrayList和List也可以使用foreach进行迭代.如果我们自己编写的类也需要使用foreach进行迭代时该怎么办呢? IE ...

随机推荐

  1. 推荐两款PC健康小软件

    一.前言 对于经常需要坐在电脑前工作一整天的人来说,健康问题是不得不关注的.下面推荐我一直在用的两款体积非常小(几百KB)的健康小软件,也许可以在无形中保护你.提醒你. 1. FadeTop 这是一款 ...

  2. 关于vim插件

    本人比较喜欢amix它集成了很多插件. 1.mru.vim:用于打开最近使用过的文件 使用命令: :MRU     打开最近的文件列表 上下箭头可以移动关标 :o 在新窗口中打开文件 2.NERD T ...

  3. 转自虫师:性能测试的 Check List

    原文地址:http://www.cnblogs.com/jackei/archive/2006/03/24/357372.html 1. 开发人员是否提交了测试申请? 2. 测试对象是否已经明确? 3 ...

  4. 【BZOJ】3916: [Baltic2014]friends

    http://www.lydsy.com/JudgeOnline/problem.php?id=3916 #include <bits/stdc++.h> using namespace ...

  5. 初识WebSocket

    众所周知,Http协议是无状态的,并且是基于Request/Response的方式与服务器进行交互,也就是我们常说的单工模式.但是随着互联 网的发展,浏览器与服务端进行双向通信需求的增加,长轮询向服务 ...

  6. CSS3两个动画顺序衔接播放

    问题描述: 第一个动画先播放,播放完成后,第二个动画紧接着播放. 解决办法: 1. 将第二个的延迟时间(animation-delay) 设置成第一个的持续时间( animation-duration ...

  7. HTML基础--JS简介、基本语法、类型转换、变量、运算符、分支语句、循环语句、数组、函数、函数调用.avi

    JS简介 1.JavaScript是个什么东西? 它是个脚本语言,需要有宿主文件,它的宿主文件是HTML文件. 2.它与Java什么关系? 没有什么直接的联系,Java是Sun公司(已被Oracle收 ...

  8. django1.9 创建项目和app并初始化项目

    创建项目: django-admin startproject  mytest04 创建app: python manage.py startapp app04 配置:settings.py 1. 2 ...

  9. 理解CSS3 transform中的Matrix(矩阵)

    一.哥,我被你吓住了 打架的时候会被块头大的吓住,学习的时候会被奇怪名字吓住(如“拉普拉斯不等式”).这与情感化设计本质一致:界面设计好会让人觉得这个软件好用! 所以,当看到上面“Matrix(矩阵) ...

  10. HTML静态网页 格式与布局

    一.position:fixed 锁定位置(相对于浏览器的位置),例如有些网站的右下角的弹出窗口. 示例: 二.position:absolute  相对于自己最近的父元素来定位的 1.外层没有pos ...