IEnumerator和IEnumerator接口的使用

在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);
        }
    }


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值