画蛇添足的 IEnumerable?

 众所周知,在 C# 中,如果要让集合支持 foreach 语句,必须实现 IEnumerable 接口,该接口只有一个方法——GetEnumerator(),这个方法返回一个 IEnumerator 的对象,实际上 foreach 是使用 IEnumerator 对象进行迭代的,使用 foreach 语句与下述语句大致相当:

        IEnumerator enumerator = myCollection.GetEnumerator();
        while(enumerator.MoveNext)
        {
                MyCollectionItem item = enumerator.Current;
                ……
        }

既然这样,为什么不直接让集合实现 IEnumerator 接口,而要通过 IEnumerable 接口来进行中转呢?于是有下面的实现:

        class MyCollection: IEnumerable, IEnumerator
        {
                …
                public IEnumerator GetEnumerator()
                {
                        return this;
                }              

                public object Current
                {
                        get { …… }
                }

                public bool MoveNext()
                { …… }

                public void Reset()
                { …… }
          }

这样简单多了,并且 foreach 仍然能够正常运作。那为什么还需要 IEnumerable 接口呢?


在迭代器模式中,有一句话:将遍历机制与集合分离开来。这话像白开水一样,不引人注目,我们很容易就把它忽略了,于是才会有上面的疑问。试想一下,如果将 IEnumerator 与集合本身放在一起,在多线程环境中,多个线程都需要遍历同一个集合,该怎么办?一个对象只有一个 Current。当然,可以利用线程的同步机制来解决,但是这个方法很笨,并且,如果不是多线程,而是嵌套的两个 foreach,那就没辄了。其实玄机就在于“将遍历机制与集合分离开来”,分离后,如果要同时遍历同一个集合,只要创建一个新的包含遍历机制的类实例即可,而这就是 IEnumerable 的意图。

不过,还有一个问题没有解决,就是如何提供多种遍历机制,比如说正序遍历和逆序遍历。这需要再转一个弯:为集合添加新的方法,返回 IEnumerable,如:

           class MyCollection: IEnumerable
           {
                 ... ...
                 public IEnumerator GetEnumerator()
                 {
                       return new NormalEnumerator(this);
                 }

                 public IEnumerable Reverse()  //注意:返回的是 IEnumerable, 不是 IEnmuerator
                 {
                       return new ReverseEnumerable(this);
                 }
           }

           class ReverseEnumerable: IEnumerable  //再次实现 IEnumerator 接口,以实现逆序遍历
           {... ... }

然后,可以在 foreach 中如下调用:

           foreach(MyCollectionItem item in myCollection.Reverse())

OK,一个标准的迭代器模式完成。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值