• 迭代器


    首先搞清楚这两个接口,可以看出这两个接口是有一定的关联的,IEnumerable的接口成员是返回一个IEnumerator接口对象,

    这个接口对象,有三个成员。

    // 摘要:

    // Exposes an enumerator, which supports a simple iteration over a non-generic

    // collection.To browse the .NET Framework source code for this type, see the

    // Reference Source.

    [ComVisible(true)]

    [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]

    public interface IEnumerable

    {

    // 摘要:

    // Returns an enumerator that iterates through a collection.

    //

    // 返回结果:

    // An System.Collections.IEnumerator object that can be used to iterate through

    // the collection.

    [DispId(-4)]

    IEnumerator GetEnumerator();

    }

     

    // 摘要:

    // Supports a simple iteration over a non-generic collection.

    [ComVisible(true)]

    [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]

    public interface IEnumerator

    {

    // 摘要:

    // Gets the current element in the collection.

    //

    // 返回结果:

    // The current element in the collection.

    object Current { get; }

     

    // 摘要:

    // Advances the enumerator to the next element of the collection.

    //

    // 返回结果:

    // true if the enumerator was successfully advanced to the next element; false

    // if the enumerator has passed the end of the collection.

    //

    // 异常:

    // System.InvalidOperationException:

    // The collection was modified after the enumerator was created.

    bool MoveNext();

    //

    // 摘要:

    // Sets the enumerator to its initial position, which is before the first element

    // in the collection.

    //

    // 异常:

    // System.InvalidOperationException:

    // The collection was modified after the enumerator was created.

    void Reset();

    }

     

    这里首先还要区分两个概念,一个是调用这个迭代器,一个是实现这个迭代器,以前傻傻分不清楚。

    先说调用这个迭代器,我们最常见的形式是使用foreach,编译器会将foreach编译来调用GetEnumeratorMoveNextCurrent

    所以一般我们有两种方法来调用,本质是一样的:

    再看看如何实现这个迭代器:

    C#1的时候:

    我们需要手工实现这个IEnumerable接口,为了实现接口,我们需要实现IEnumerator接口,生成一个内部类,然后再返回一个这个对象实例即可

    我们发现,为了实现一个迭代器,我们需要做很多的工作,但是我们能看到具体的细节,可以看出,如果我们调用迭代器的时候,就跟调用方法一样,每调用一次,返回一个结果。

     

    C#2.0的时候,实现迭代器,因为以前实现迭代器太繁琐,所以编译器打算自己跟我们把这些工作做好:

    我们发现,简单了很多,不需要自己写内部类等,只需要特殊的关键字yield即可。

     

    疑难问题:

    1)书上说,迭代一个类,可使用方法GetEnumerator(),返回类型为IEnumerator,迭代一个类成员,则返回IEnumerable

    迭代一个类,自然要实现IEnumerable接口,这个接口的成员就是GetEnumerator,自然就应该返回IEnumerator

    迭代一个类成员,因为这个成员方法不会像类一样去实现什么接口,所以肯定要返回IEnumerable对象,所以内部也必须要能够帮助完成这一点,

    要么有这么一个实现了这个接口的子类,要么使用yield,本质上一样的,因为只有IEnumerable才能被迭代,IEnumerator不能迭代。

     

    2)不能在迭代块中写任何在方法调用时需要立即执行的代码-比如说参数验证。

    这点可以这样来理解,因为在正式迭代之前,也就是调用MoveNext()方法之前,yield语句等才开始调用,所以就相当于即需加载一样。

     

    3)关于finally块执行流程,其实很简单,如果是通过foreach来调用的,那么在yield break的时候,就会执行finally语句块,如果手动调用movenext()方法,则不会自动调用,

    需要手工调用dispose方法,释放资源,这里IEnumerator跟其泛型是不一样的,IEnumerator<T>继承了IDisposable接口。迭代块里面的finally中的语句,就是最终Dispose方法

    应该调用的地方,所以就解释了之前的疑惑:在迭代完成后会释放迭代器,这里是针对方法返回IEnumerable<T>的情况,如果是 类应该也是一样,也可以加finally吧,比如读取IO

    资源的时候,在这里可以进行释放。

     

    4)不能理解迭代器的优点在哪。

    举一点例子,如果是查询文件,找到所有行,如果调用File.ReadAllLines,以及实现一个迭代器Array.FindAll, 后者在文件较大的时候就优势体现出来了,

    后者是流线型处理的,一行一行读过来。

    访问一个聚合对象的内容而无需暴露它的内部表示,所以可以提供聚合对象的多种遍历。

     

    https://files.cnblogs.com/files/monkeyZhong/NewOverrideDemo.zip

     

     

     

     

  • 相关阅读:
    C#拾遗系列(2):属性
    都江堰我永远支持你
    【号外】2011 Autodesk开发者日又来啦~~
    DB_RUNRECOVERY: Fatal error, run database recovery StackTrace问题的解决办法
    [书友交流] <Autodesk 地理信息系统解决方案FDO、MapGuide、AutoCAD Map 3D二次开发指南>读书交流贴
    Autodesk Infrastructure Map Server 2012 SP1 Released!
    Map3D中获取地图中心及Zoom到新的中心点
    Introduction to MapGuide OpenSource – from FOSS4G in Denver
    获取选中地物的Geometry对象,及把Geometry对象显示在地图上
    [在线技术活动]Civil 3D 部件编辑器详解
  • 原文地址:https://www.cnblogs.com/monkeyZhong/p/8309965.html
Copyright © 2020-2023  润新知