IEnumerable 接口

IEnumerable 接口

公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。重复操作。

迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次迭代的初始值。

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            charlist mycharlist = new charlist("hello world");
            foreach (var c in mycharlist)
            {
                Console.Write(c);
            } 
            Console.ReadLine();
        }
    }
    class charlist : IEnumerable
    {
        public string TargetStr { get; set; }
        public charlist(string str) { 
            this.TargetStr = str; 
        }
        public IEnumerator GetEnumerator()
        {     
            return new CharIterator(this.TargetStr);
        }
    }
    class CharIterator : IEnumerator    //迭代器的实现
    {
        public string TargetStr { get; set; }
        public int position { get; set; }        //存储当前的迭代位置
        public CharIterator(string targetStr) 
        { 
            this.TargetStr = targetStr; 
            this.position = this.TargetStr.Length; 
        }
        public object Current {  //当前迭代位置的元素
            get { 
                if (this.position == -1 || this.position == this.TargetStr.Length) 
                { 
                    throw new InvalidOperationException();
                } 
                return this.TargetStr[this.position]; 
            }
        }
        public bool MoveNext() {   //更新迭代位置,并且查看下一个迭代位置是不是有效的。
            if (this.position != -1) {
                this.position--; 
            } 
            return this.position > -1; 
        }
        public void Reset() {
            this.position = this.TargetStr.Length;
        }
    }
}


        代码首先执行到foreach语句的charList处获得迭代器CharIterator的实例,然后代码执行到in会调用迭代器的MoveNext方法,最后变量c会得到迭代器Current属性的值;前面的步骤结束后,会开始一轮新的循环,调用MoveNext方法,获取Current属性的值。

        要实现一个迭代器就要实现IEnumerator接口,然后实现IEnumerator接口中的MoveNext、Reset方法和Current属性。

C#如何实现自定义集合的IEnumerable 和 IEnumerator 接口并使用foreach访问自定义集

static void Main(string[] args)
{
    int[] array = new int[] { 5,4,3,2,1};
    foreach (int i in array)
        Console.WriteLine("Number:"+i);
    Console.ReadKey();            
}
/**
 * -------------执行结果-------------
 * Number:5
 * Number:4
 * Number:3
 * Number:2
 * Number:1
 * -------------执行结果-------------
 */


 

问题:为什么使用foreach可以遍历出数组中的所有元素呢?                  

原因:数组是可枚举类型,它可以按需提供枚举数,枚举数可以依次返回请求的数组的元素。而foreach结构被设计用来和可枚举类型一起使用,只要给foreach的遍历对象是可枚举类型,则她就会执行如下行为:

  1. 通过调用GetEnumerator方法获取对象(如:数组)的枚举数(即数组中的元素值)
  2. 从枚举数中请求每一项并把她作为迭代遍历

因为数组是可枚举类型,所以我就使用使用IEnumerator接口来实现枚举数以模仿foreach的循环遍历

static void Main(string[] args)
{
    int[] array = new int[] { 5,4,3,2,1};
    IEnumerator ie = array.GetEnumerator();//获取枚举数
    while (ie.MoveNext())//移动下一项
    {
        //最初,枚举数定位在集合中第一个元素前,在此位置上,Current 属性未定义
        //因此,在读取 Current 的值之前,必须调用 MoveNext 方法将枚举数提前到集合的第一个元素
        int i = (int)ie.Current;//获取当前项
        Console.WriteLine("Number:" + i);
    }      
}
   /**
    * -------------执行结果-------------
    * Number:5
    * Number:4
    * Number:3
    * Number:2
    * Number:1
    * -------------执行结果-------------
    */


 

实现IEnumerable 和 IEnumerator 接口                                                                    

以下示例演示如何实现自定义集合的IEnumerable 和 IEnumerator 接口,在此示例中,没有显式调用这些接口的成员,但实现了它们,以便支持使用 foreach循环访问该集合

要点:

  1. 显示实现IEnumerable接口的GetEnumerator成员函数
  2. 显示实现IEnumerator接口的Current,Reset(),MoveNext()

示意图:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{    
    // 实现IEnumerator接口
    public class PersonIEnumerator : IEnumerator
    {
        string[] Person;
        int position = -1;
        public PersonIEnumerator(string[] thePersons)
        {
            Person = new string[thePersons.Length];
            for (int i = 0; i < thePersons.Length; i++)
            {
                Person[i] = thePersons[i];
            }
        }
        //IEnumerator接口的特性1
        public object Current
        {
            get { return Person[position]; }
        }
        //IEnumerator接口的特性2
        public bool MoveNext()
        {
            if (position < Person.Length - 1)
            {
                position++;
                return true;
            }
            else
                return false;
        }
        //IEnumerator接口的特性3
        public void Reset()
        {
            position = -1;
        }
    }
    //实现IEnumerable接口
    public class MyPersons : IEnumerable
    {
        string[] strArr = new string[] { "周星驰", "莫言", "贝克汉姆", "林志颖" };
        //返回IEnumerator类型的对象
        public IEnumerator GetEnumerator()
        {
            return new PersonIEnumerator(strArr);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyPersons mp = new MyPersons();
            foreach (string name in mp)
            {
                Console.WriteLine("{0}", name);
            }
            Console.ReadKey();            
        }        
    }
    /**
     * -------------执行结果-------------
     * 周星驰
     * 莫言
     * 贝克汉姆
     * 林志颖
     * -------------执行结果-------------
     */
} 
 

注:C# 语言的 foreach 语句隐藏了枚举数的复杂性。因此,建议使用 foreach,而不直接操作枚举数

 

 

 

 

你可能感兴趣的:(IEnumerable 接口)