引言

IEnumerable是可枚举的所有非泛型集合的基接口, IEnumerable包含一个方法GetEnumerator(),该方法返回一个IEnumerator;IEnumerator提供通过Current属性以及MoveNext()和Reset()方法来循环访问集合的功能。

IEnumerable 接口

公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。接口源码如下:

public interface IEnumerable
{
[DispId(-), __DynamicallyInvokable]
IEnumerator GetEnumerator();
}

IEnumerator 接口

支持对非泛型集合的简单迭代。接口源码如下:

public interface IEnumerator
{
[__DynamicallyInvokable]
bool MoveNext();
[__DynamicallyInvokable]
object Current { [__DynamicallyInvokable] get; }
[__DynamicallyInvokable]
void Reset();
}

举例说明

示例演示了通过实现IEnumerable和IEnumerator接口来循环访问自定义集合的最佳实践。

定义一个简单的实体类:

public class Person
{
public Person(string name, int age)
{
this.Name = name;
this.Age = age;
}
public string Name;
public int Age;
}

定义一个实体类的集合,继承IEnumerate:

 public class People : IEnumerable
{
private Person[] _people;
public People(Person[] pArray)
{
_people = new Person[pArray.Length];
for (int i = ; i < pArray.Length; i++)
{
_people[i] = pArray[i];
}
}
/// <summary>
/// GetEnumerator方法的实现
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public PeopleEnum GetEnumerator()
{
return new PeopleEnum(_people);
}
}

定义一个枚举器,继承IEnumerator:

public class PeopleEnum : IEnumerator
{
public Person[] _people; /// <summary>
/// 枚举器位于第一个元素之前直到第一个MoveNext()调用。
/// </summary>
private int position = -;
public PeopleEnum(Person[] list)
{
_people = list;
} public bool MoveNext()
{
position++;
return position < _people.Length;
} public void Reset()
{
position = -;
} object IEnumerator.Current => Current; public Person Current
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}

具体调用:

 Person[] peopleArray = new Person[]
{
new Person("张三", ),
new Person("李四", ),
new Person("王五", ),
};
People peopleList = new People(peopleArray); foreach (Person p in peopleList)
Console.WriteLine(p.Name + "\t" + p.Age);

输出:

其中,上边调用中foreach等价于

IEnumerator enumeratorSimple = peopleList.GetEnumerator();
while (enumeratorSimple.MoveNext())
{
Person p = enumeratorSimple.Current as Person;
Console.WriteLine(p?.Name + "\t" + p?.Age);
}

通过例子,可以得出:

  • 实现一个自定义集合,继承于IEnumerate,必须实现一个枚举器;
  • C# 语言的foreach语句隐藏了枚举数的复杂性,因此, 建议foreach使用, 而不是直接操作枚举器;
  • 枚举器可用于读取集合中的数据,但不能用于修改基础集合。

总结

IEnumerable代表继承此接口的类(比如ArrayList,IList,List<T>等)可以获取一个IEnumerator来实现枚举这个类中包含的集合中的元素的功能,是 .NET Framework 中最基本的集合访问器。在编程中,Lambda表达式通过Select()或者Where()返回的变量为IEnumerate<T>,此时我们可以通过foreach遍历。希望本文对你有所帮助,下一篇介绍Lambda中的Select和Where,感兴趣的朋友可以加关注,欢迎留言交流!

IEnumerable和IEnumerator详解的更多相关文章

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

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

  2. IEnumerable和IEnumerator 详解 (转)

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

  3. IEnumerable和IEnumerator 详解

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

  4. IEnumerable和IEnumerator 详解 【转】

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

  5. 转载 IEnumerable和IEnumerator 详解

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

  6. IEnumerable 使用foreach 详解

    自己实现迭代器 yield的使用 怎样高性能的随机取IEnumerable中的值 我们先思考几个问题: 为什么在foreach中不能修改item的值? 要实现foreach需要满足什么条件? 为什么L ...

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

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

  8. IEnumerator和IEnumerable详解

    IEnumerator和IEnumerable 从名字常来看,IEnumerator是枚举器的意思,IEnumerable是可枚举的意思. 了解了两个接口代表的含义后,接着看源码: IEnumerat ...

  9. IEnumerable<T> 接口和GetEnumerator 详解

    IEnumerable<T> 接口 .NET Framework 4.6 and 4.5   公开枚举数,该枚举数支持在指定类型的集合上进行简单迭代. 若要浏览此类型的.NET Frame ...

随机推荐

  1. 使用“反向传播”迭代法求解y=√10

    X=√10,求X,也就是求Y=10 =X2 , X是多少. *重要的思想是,如何转化为可迭代求解的算法问题. *解数学问题,第一时间画图,求导,“直线化”. Y = X2 假如已知Y = 10 ,要求 ...

  2. 学习笔记15_ASP母版页

    *网页母版页设计通用样式#header:{height:100px;width:1000px}#leftDiv:{float:left;width:200px}#mainDiv:{margin-lef ...

  3. [2018-01-12] laravel--路由(路由与控制器)

    路由只用来接收请求 目前我们大致了解了laravel,在开始一个Http程序需要先定义路由.之前的例子中,我们的业务逻辑都是在路由里实现的,这对于简单的网站或web应用没什么问题,当我们需要扩大规模, ...

  4. 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~

    简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring ...

  5. 【gradle使用—gradle介绍】

    Gradle基本组件  Gradle是一个框架,定义了一套自己的规则,所以要搞清楚Gradle,必须要遵守它设计的原则,下面我们要先搞清楚一些Gradle的概念: Gradle中,每一个待编译的工程是 ...

  6. 最新JetBrains PyCharm 使用教程--创建或导入项目(二)

    Python简介 Python是一种非常流行的开源编程语言.得益于无尽的模块选项,Python今天广泛用于脚本语言.Web开发.移动和桌面在许多领域.随着人工智能的复兴,数据科学的崛起,Python更 ...

  7. Unity入门--实用知识

    目录 1. VS适配 2.实用快捷操作 3.Unity API文档 4.项目整理 1. VS适配 让你的VS完美支持Unity的脚本编写可以让你写起C#脚本来事半功倍,比如代码补全功能,可以参考下面这 ...

  8. java 实现一个死锁

    /** * 死锁:两个或多个线程在执行过程中,相互争夺资源而造成的一种互相等待的现象 * 实现一个死锁 * <p> * <p> * 查看死锁 * 1. 在当前类的文件夹下,打开 ...

  9. Phone Code

    Polycarpus has n friends in Tarasov city. Polycarpus knows phone numbers of all his friends: they ar ...

  10. C++中对C的扩展学习新增语法——强制类型转换

    类型转换:主要进行指针类型转换,因为在C++中,不同类型指针不允许隐式转换,任何一个程序中如果出现了大量的类型转换,说明该程序不是太好的程序. 注意事项: 不同类型指针不允许隐式转换: void* 类 ...