`

IEnumerable和IEnumerator接口的使用

阅读更多

注意:http://blog.csdn.net/shenyuangong/archive/2008/08/23/2819517.aspx

 

注:IEnumerable接口有一个方法GetEnumerator。该方法返回一个IEnumerator对象。该对象支持枚举对象方法包括MoveNext() 和Reset(). 另外还有一个Current属性。但是该属性开始的时候指向序列的第一个对象之前。必须用MoveNext()方法移到第一个位置。

 

 

-------------------------------------------------------------------

 

转自:http://hi.baidu.com/l496501043/blog/item/4c69df809abfe9b46d8119c8.html

 

一、示例:

在C#中,凡是实现了IEnumerator接口的数据类型都可以用foreach语句进行迭代访问,可是,对于自定义类型如何实现这个接口以支持foreach的迭代呢?
* 要实现这个功能,先来看看IEnumerable和IEnumerator接口的定义:

public interface IEnumerable
{
      //IEnumerable只有一个方法,返回可循环访问集合的枚举数。
      IEnumerator GetEnumerator() ;
}
public interface IEnumerator
{
      // 方法
      //移到集合的下一个元素。如果成功则返回为 true;如果超过集合结尾,则返回false。
      bool MoveNext();
     // 将集合设置为初始位置,该位置位于集合中第一个元素之前
      void Reset();

      // 属性:获取集合中的当前元素
      object Current { get; }
}

namespace IEnumberableTest
{
    class Program
    {
        static void Main(string[] args)
        {
            myEnum enum1 = new myEnum(20);

            foreach (point p in enum1)
            {
                Console.WriteLine("(" + p.x.ToString() + "," + p.y.ToString() + "," + p.z.ToString() + ")");
            }

            Console.Read();
        }
    }

    //一个结构体,用于类myEnum
    struct point
    {
        public int x;
        public int y;
        public int z;
    }

    //一个派生于IEnumerable和IEnumerator接口的自定义类
    class myEnum : IEnumerable, IEnumerator
    {
        //定义索引
        private int index;

        //定义一个point结构的数组
        private point[] points;

        //类的构造函数,用于初始化point结构数组
        public myEnum(int numofpoint)
        {
            this.index = -1;
            points = new point[numofpoint];

            for (int i = 0; i < points.Length; i++)
            {
                points[i].x = i;
                points[i].y = i * i;
                points[i].z = i * i * i;
            }
        }

        //实现IEnumerable接口的GetEnumerator方法,返回一个IEnumerator,这里返回我们的自定义类,因为要对这个类的对象进行迭代
        public IEnumerator GetEnumerator()
        {
            return (IEnumerator)this;
        }

        //实现IEnumerator接口的Reset方法,将集合索引置于第一个元素之前
        public void Reset()
        {
            index = -1;
        }

        //实现IEnumerator接口的Current属性,返回一个自定义的point结构,即point数组的第index元素
        public object Current
        {
            get
            {
                return points[index];
            }
        }

        //实现IEnumerator接口的MoveNext方法,用于向前访问集合元素,如果超出集合范围,返回false
        public bool MoveNext()
        {
            index++;
            return index >= points.Length ? false : true;
        }

    }
}

二、区别:

IEnumerable和IEnumerator有什么区别?这是一个很让人困惑的问题(在很多forum里都看到有人在问这个问题)。研究了半天,得到以下几点认识:

1、一个Collection要支持foreach方式的遍历,必须实现IEnumerable接口(亦即,必须以某种方式返回IEnumerator object)。

2、IEnumerator object具体实现了iterator(通过MoveNext(),Reset(),Current)。

3、从这两个接口的用词选择上,也可以看出其不同:IEnumerable是一个声明式的接口,声明实现该接口的class是“可枚举(enumerable)”的,但并没有说明如何实现枚举器(iterator);IEnumerator是一个实现式的接口,IEnumerator object就是一个iterator。

4、IEnumerable和IEnumerator通过IEnumerable的GetEnumerator()方法建立了连接,client可以通过IEnumerable的GetEnumerator()得到IEnumerator object,在这个意义上,将GetEnumerator()看作IEnumerator object的factory method也未尝不可。


IEnumerator   是所有枚举数的基接口。  
   
枚举数只允许读取集合中的数据。枚举数无法用于修改基础集合。  
   
最初,枚举数被定位于集合中第一个元素的前面。Reset   也将枚举数返回到此位置。在此位置,调用   Current   会引发异常。因此,在读取   Current   的值之前,必须调用   MoveNext   将枚举数提前到集合的第一个元素。  
   
在调用   MoveNext   或   Reset   之前,Current   返回同一对象。MoveNext   将   Current   设置为下一个元素。  
   
在传递到集合的末尾之后,枚举数放在集合中最后一个元素后面,且调用   MoveNext   会返回   false。如果最后一次调用   MoveNext   返回   false,则调用   Current   会引发异常。若要再次将   Current   设置为集合的第一个元素,可以调用   Reset,然后再调用   MoveNext。  
   
只要集合保持不变,枚举数就将保持有效。如果对集合进行了更改(例如添加、修改或删除元素),则该枚举数将失效且不可恢复,并且下一次对   MoveNext   或   Reset   的调用将引发   InvalidOperationException。如果在   MoveNext   和   Current   之间修改集合,那么即使枚举数已经无效,Current   也将返回它所设置成的元素。  
   
枚举数没有对集合的独占访问权;因此,枚举一个集合在本质上不是一个线程安全的过程。甚至在对集合进行同步处理时,其他线程仍可以修改该集合,这会导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。

分享到:
评论

相关推荐

    C# IEnumerable和IEnumerator接口浅析

    Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行遍历,IEnumerable和IEnumerator接口我有时候也有点迷糊,按官方的解释,IEnumerable是枚举器接口,IEnumerator是迭代器接口,从字面意思来看相差不大...

    C#自建类实现集合接口IEnumerable, IEnumerator

    ### C#自建类实现集合接口 `IEnumerable` 和 `IEnumerator` 在C#中,自定义一个集合类并使其能够支持常见的集合操作(如迭代、添加、删除等)是非常实用的功能。下面将详细介绍如何通过实现 `IEnumerable` 和 `...

    基于C#中IDisposable与IEnumerable、IEnumerator的应用

    当需要遍历集合或自定义数据流时,可以使用IEnumerable接口和IEnumerator接口。这两个接口提供了遍历数据集的能力。 1. 让类继承`IEnumerable&lt;T&gt;`或`IEnumerable`接口,这样你的类就成为了可迭代的对象。这将强制你...

    C#中可枚举类型详解

    我们经常使用的大多数集合实际上都已经实现了枚举的接口IEnumerable和IEnumerator接口,这样才能使用foreach迭代,有些是含有某种抽象了枚举细节的接口:ArrayList类型有索引,BitArray有Get方法,哈希表和字典有键...

    C#foreach原理

    如果该类型是一个泛型集合,还可能需要实现IEnumerable和IEnumerator接口以支持类型安全的枚举。 具体到代码实现,我们可以参考文章中给出的Person类的示例。Person类包含一个字符串数组_names,如果我们希望...

    Net面向对象程序设计枚举集合PPT教案学习.pptx

    此外,尽管使用IEnumerable和IEnumerator接口可以实现枚举,但这种方式存在性能和类型安全问题。当Current返回object类型时,对于值类型的数据需要进行装箱和拆箱,大量操作时会影响效率。同时,由于返回的是object...

    C#中IEnumerable接口用法实例分析

    IEnumerator接口包含三个方法:`MoveNext()`、`Reset()`和`Current`属性。 - `MoveNext()`:这个方法将枚举器向前移动到集合中的下一个元素。如果已到达集合的末尾,`MoveNext()`将返回`false`。 - `Reset()`:此...

    C# 编程基础

    在C#中,`IEnumerable`和`IEnumerator`接口被用来支持集合的遍历。通过实现这些接口,可以创建可枚举的集合。 ##### 1. `IEnumerable`接口 - **定义**:`IEnumerable`接口用于声明一个集合是可枚举的。这意味着...

    IEnumerable<T>、IEnumerable、ICollection<T>、IList<T>、ObservableCollectin<T>和Collection<T>得关系。

    `IEnumerator&lt;T&gt;`接口提供了`MoveNext()`、`Reset()`和`Current`属性,用于控制遍历过程和访问当前元素。`IEnumerable&lt;T&gt;`和`IEnumerable`接口的区别在于前者是泛型,后者是为非泛型集合设计的,但两者都支持`...

    c#面试题集锦

    要使一个类支持foreach遍历,需要实现IEnumerable和IEnumerator接口。这些接口提供了遍历集合的机制。可以通过实现GetEnumerator方法和MoveNext、Reset等方法来实现遍历。 7. 程序中有什么错? 在静态函数中只能...

    yield总结与实例

    一、实现foreach的关键: 必须为包含有GetEnumerator()...四、如果返回类型为IEnumerator编译时会实现一个实现了IEnumerator接口的类 五、同理如果返回类型为IEnumerable编译时会实现一个实现了IEnumerable接口的类

    C#接口实验报告

    - **集合接口使用** - 使用`List&lt;T&gt;`集合来存储水果对象。 - 实现`IEnumerable`接口,并重写`GetEnumerator()`方法。 - `GetEnumerator()`方法返回一个实现了`IEnumerator`接口的枚举器对象,用于迭代集合中的...

    自定义类型实现系统接口的例子(一)

    本篇文章将深入探讨如何通过自定义类型实现四个关键的系统接口:`IComparable`、`IComparer`、`IEnumerable`和`IEnumerator`以及`IDisposable`。这些接口在各种场景下都有广泛的应用,例如数据排序、枚举遍历和资源...

    C#中的IEnumerable简介及简单实现实例

    总的来说,`IEnumerable`接口和`IEnumerator`接口是C#中实现迭代的关键,它们使得开发者能够方便地遍历任何可枚举类型的集合,包括自定义的集合类型。在给定的例子中,通过自定义迭代器,我们能够以反向顺序遍历字符...

    C#迭代器及Unity协程实例解析

    C#中的迭代器封装在IEnumerable和IEnumerator和他们的泛型接口中。 IEnumerable:定义了一个可以获取IEnumerator的方法—GetEnumerator()。 //IEnumerable的代码实现 public interface IEnumerable { ...

    C# System.Collections 非泛型接口方法解析.pdf

    本文将深入解析C#中的一些关键非泛型集合接口,如`IEnumerable`、`IEnumerator`、`IComparer`、`IEqualityComparer`、`IStructuralComparable`、`IStructuralEquatable`、`ICollection`、`IList`以及`IDictionary`...

    Net面向对象程序设计枚举集合PPT学习教案.pptx

    .NET中存在两种类型的枚举器:非泛型的`IEnumerator/IEnumerable`接口和泛型的`IEnumerator&lt;T&gt;/IEnumerable&lt;T&gt;`接口。非泛型版本可以返回任何类型的元素,但可能导致类型转换的开销,而泛型版本则提供了类型安全的...

Global site tag (gtag.js) - Google Analytics