IEnumerator和IEnumerator接口的使用
来源:互联网 发布:无限法则 知乎 编辑:程序博客网 时间:2024/05/19 13:05
在C#中凡是实现了IEnumerator接口的数据类型都可以用foreach语句进行迭代访问.可是自定义类型如何实现IEnumerator接口来支持foreach迭代呢?
要实现这个功能,先来看看IEnumerable和IEnumerator接口的定义.
public interface IEnumerable
{
//IEnumerable只有一个方法,返回可循环访问集合的枚举数.
IEnumerator GetEnumerator();
}
public interface IEnumerator
{
//移动到集合的下一个元素,如果成功返回true,如果失败返回false
bool MoveNext();
//将集合重置为初始位置,这个位置在集合第一个元素之前(类似于-1的状态)
void Reset();
//属性,访问集合的当前元素
object Current{get;}
}
IEnumerator是所有枚举数的基接口.枚举数只允许读取集合中的数据(是只读的,在遍历过程中不可进行修改).枚举数无法用于修改基础集合.最初,枚举数被定位于集合第一个元素的前面.Reset()也将枚举数设置到此位置.在此位置调用Current会引发异常.因此在调用Current之前,必须先调用MoveNext(),将枚举数提前到集合第一个元素,在调用MoveNext和Reset这前,Current会返回同一个对象,MoveNext将Current设置为下一个元素,当使用MoveNext到集合的末尾时,枚举数会被设置到集合最后一个元素的后面.,这时调用MoveNext会返回false.如果调用MoveNext返回false,此时再调用Current会引发一个异常.如果要再次让Current访问集合的第一个元素,应先调用Reset然后再调用MoveNext;
注:实现上是把位于集合首部和尾部的特殊判断转移到了MoveNext函数中.这样我们在使用IEnumerator这个接口会,具体的实现会很漂亮,省事.
枚举数没有对集合的独占访问权,因此枚举一个集合在本质上不是一个线程安全的过程.在枚举一个集合的过程中,其它线程仍可以修改该集合.这会导致枚举数引发异常.如果要在枚举过程中保证线程安全,可以在整个枚举过程事锁定集合,或者捕捉由于其他纯种进行的更改而引发的异常.
下面来总结一下IEnumerable和IEnumerator的区别
1.一个集合要想通过foreach进行迭代就必须实现IEnumearble接口(必须以某种方式返回一个IEnumerator对象)
2.IEnumerator对象具体来实现了一个迭代器
3.从这两个接口的用词选择上可以看出:IEnumerable是一个声明式接口,声明实现该接口的类是可以枚举的,但没有说明如何实现枚举器.
IEnumerator是一个实现式接口,IEnumerator对象就是一个迭代器.
4.IEnumerable和IEnumerator接口通过IEnumerable接口的GetEnumerator方法建立连接,客户可以通过IEnumerable接口的GetEnumerator方法来得到一个IEnumerator对象
在这个意思上可以将GetEnumerator方法看成是IEnumerator的工厂方法.
public class Person { public string Name { get; set; } public string Sex { get; set; } } //枚举器的实现 class PersonEnumerator:IEnumerator<Person> { int _currentIndex; Person[] _psersons; public PersonEnumerator(Person[] _psersons) { this._psersons = _psersons; _currentIndex = -1; } public Person Current { get { if (_currentIndex < 0 || _currentIndex > _psersons.Length) { throw new InvalidOperationException("索引越界"); } return _psersons[_currentIndex]; } } object System.Collections.IEnumerator.Current { get { if (_currentIndex < 0 || _currentIndex > _psersons.Length) { throw new InvalidOperationException("索引越界"); } return _psersons[_currentIndex]; } } public bool MoveNext() { _currentIndex++; return _currentIndex < _psersons.Length; } public void Reset() { _currentIndex = -1; } public void Dispose() { } } public class Persons : IEnumerable<Person> { Person[] _persons; public Persons() { _persons = new Person[] { new Person { Name = "1", Sex="---", }, new Person { Name = "2", Sex="---", }, }; } public IEnumerator<Person> GetEnumerator() { return new PersonEnumerator(_persons); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new PersonEnumerator(_persons); } }
- IEnumerator和IEnumerator接口的使用
- 使用IEnumerable和IEnumerator接口
- IEnumerable和IEnumerator的使用
- IEnumerable 和 IEnumerator 接口
- IEnumerable 和 IEnumerator 接口
- IEnumerable 和 IEnumerator 接口
- IEnumerable和IEnumerator接口
- IEnumerable 和 IEnumerator 接口
- IEnumerator和IEnumerable是怎样使用的
- C#中的IEnumerable和 IEnumerator的使用
- 使用 Hashtable(哈希表)和 IEnumerator 接口 示例
- 迭代器学习之一:使用IEnumerable和IEnumerator接口
- 使用IEnumerator,IEnumerable接口制作一个简单的迭代器
- 协程(IEnumerator)的使用
- IEnumerator和IEnumerable的关系
- IEnumerable和IEnumerator的理解
- IEnumerable和 IEnumerator的区别
- IEnumerator和IEnumerable的区别
- 字符串反向输出的几种方法
- Android事件—单选按键和下拉按键
- 在没有QT环境的windows机器上发布QT程序的方法
- Linux常用命令大全
- hdu 2159
- IEnumerator和IEnumerator接口的使用
- Android 4.0 横竖屏切换注意事项
- 在Windows平台为qt应用程序设置图标
- C++中高并发使用线程不安全类库的一种方法
- rownum等的介绍
- linux下mount命令的用法
- gcc的小技巧
- glPushMatrix 和glPopMatrix图解 ----求别笑
- 内存管理详解