引言

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. char 、signed char、unsigned char

    看如下代码: char c = -1; signed char sc = -1; unsigned char uc = -1; printf("c=%d, sc=%d, uc=%d, cx= ...

  2. Rest_Framework之认证、权限、频率组件源码剖析

    一:使用RestFramwork,定义一个视图 from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet ...

  3. weex不支持类的动态追加

    做一个weex项目时遇到需要根据状态动态改变样式的功能,本来想通过判断属性追加类的方式实现,如下: :class="['long-news',{'bold-txt':noRead}]&quo ...

  4. 替换word中的数据,并给导入word的图片添加水印

    public static void ExportWord(string tempFilePath, string outPath, Dictionary<string, string> ...

  5. 爬虫基本库的使用---requests库

    使用requests---实现Cookies.登录验证.代理设置等操作 处理网页验证和Cookies时,需要写Opener和Handler来处理,为了更方便地实现这些操作,就有了更强大的库reques ...

  6. C语言I作业05

    问题 答案 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-4/homework/9772 我在 ...

  7. [考试反思]1024csp-s模拟测试85:以为

    愈发垃圾. T1基本全场切(除了RP<-inf的zkt和把人擦) 然后T2想了半天逐渐趋近于正解,但是因为数据有问题锅了25分,没什么好说的.T3连题意转化都没有完成.括号匹配转为+1/-1做法 ...

  8. 零基础Linux入门之《Linux就该这么学》

    本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的高质量Linux技术自学教程,极其适合用于Linux技术入门教程或讲课辅助教材,目前是国内最值得去读的Linux教材,也是最有价值 ...

  9. PTA刷题记录(1)

    团队天梯赛-------(2)分值:20 题目要求:你写个程序把给定的符号打印成沙漏的形状.例如给定17个“*”,要求按下列格式打印 ***** ***   *  *** ***** 所谓“沙漏形状” ...

  10. OTA升级详解(三)

    君子知夫不全不粹之不足以为美也, 故诵数以贯之, 思索以通之, 为其人以处之, 除其害者以持养之: 出自荀子<劝学篇> 终于OTA的升级过程的详解来了,之前的两篇文章OTA升级详解(一)与 ...