C# IEnumerable、IEnumerator和yield关键字详解
来源:互联网 发布:sql库位库存分配 编辑:程序博客网 时间:2024/06/07 00:59
本文章仅为个人学习总结,如有错误请指正。
可枚举类型就是可以通过foreach循环进行运算的,支持GetEnumerator方法的(可以有参数)的类,那么这个类可以称为可枚举类型
本文章具有以下知识点
1.实现IEnumerator和IEnumerable接口。
2.yield关键字
3.foreach步骤。
会由一篇文章讲解List是如何实现foreach循环的和简单的List内部实现代码。
一、IEnumerable和IEnumerator
1.IEnumerable
该枚举数支持在非泛型集合上进行简单迭
1.1IEnumerator GetEnumerator()
返回一个循环访问集合的枚举数,可用于循环访问集合的 System.Collections.IEnumerator 对象,这个对象具体实现如何进行迭代(遍历)。
2.IEnumerator:
支持对非泛型集合的简单迭代。
2.1object Current { get; }
获取集合中的当前元素。
2.2 bool MoveNext();
将枚举数推进到集合的下一个元素。
如果枚举数成功地推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false。
2.3void Reset();
将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
以上是微软给出的解释,我的理解 IEnumerable 实现这个接口的类型支持某个类型的集合或数组的迭代。具体如何迭代由实现IEnumerator接口的类来确定 IEnumerator 确定指定的类(该类保证了某个类的集合具有迭代功能)如何进行迭代。 简单的说:B类型保证A类型的集合具有迭代功能,C类型去确定B类型如何进行简单的迭代(迭代返回的对象实际为A类型)
微软给出的Demo:
Person是A类型。
People是B类型,实现接口IEnumerable,支持对Person集合上进行简单迭代.
PeopleEnum是C类型,实现接口IEnumerator,实现Person集合的类型People是如何进行迭代的。
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]; } } public IEnumerator 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; } public object Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } }
yield关键字,两种迭代器
yield关键字是一个语法糖,可以省略创建实现IEnumerator接口的类。
在创建可枚举类型(也就是实现了IEnumerable)接口的类型,还需要创建一个实现IEnumerator的类型,来进行确定如何实现迭代过程。
1.构建迭代器
迭代器就是一个类型的成员方法,方法名称必须为GetEnumerator(),返回值必须为IEnumerator。
但是不需要实现去创建实现IEumerator接口的类型去确定如何实现三个成员。
使用yield关键字后return 指定的对象后,当前位置会进行保存下来,下次调用的时候会从这个位置开始执行。
说白了,C#编译器会在编译后生成一个密封的类,该类实现了IEnumerator接口,所以是语法糖。
public class Person { public Person(string fName, string lName) { this.firstName = fName; this.lastName = lName; } public string firstName; public string lastName; } public class People { public People(Person[] persons) { _persons = persons; } private Person[] _persons; public IEnumerator GetEnumerator() { for (int i = 0; i < _persons.Length; i++) { yield return _persons[i]; } } }
2.构建命名迭代器 yield实际可以和任何方法一起使用,无论方法名称、参数名称,只要返回类型为IEnumerable接口就可以。 C#编译器内部会自动生成一个嵌套的密封类,这个类实现了接口IEnumerator和IEnumerable接口,说白了也就是一个List的部分功能。List集合实现迭代,也具有具体的迭代方法
public class Person { public Person(string fName, string lName) { this.firstName = fName; this.lastName = lName; } public string firstName; public string lastName; } public class People { private Person[] _people; public People(Person[] pArray) { _people = new Person[pArray.Length]; for (int i = 0; i < pArray.Length; i++) { _people[i] = pArray[i]; } } public IEnumerable GetPerson() { foreach (var item in _people) { yield return item; } } }
foreach的执行步骤
foreach中var 实际是类型推断,使用使用了实际的类型,如Person那么发生理氏转换
1.执行到People后会内部调用GetEnumerator()返回,只调用一次
2.执行in,实际就是调用MoveNext,判断下一个集合元素是否存在
3.如果为true则通过属性Current获取迭代后的元素。
4.如果为false则结束迭代
- C# IEnumerable、IEnumerator和yield关键字详解
- C# IEnumerable和IEnumerator 详解
- C# IEnumerable和IEnumerator 详解
- C# IEnumerator, IEnumerable, and Yield
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解 .
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- IEnumerable和IEnumerator 详解
- 请求网页图片
- HDU
- 数据结构思维 第三章 `ArrayList`
- QToolButton 工具按钮
- 2017/9/2 离线赛
- C# IEnumerable、IEnumerator和yield关键字详解
- SPI总线接口
- doxygen的安装与配置
- 统计学习方法五 决策树分类
- WOJ1133-Candies
- 慕课:Linux达人养成计划I—命令
- python---字典
- VC编译问题:0xC0000005
- Android关键字persistent