C# - 迭代器

来源:互联网 发布:java登录界面图片 编辑:程序博客网 时间:2024/04/29 04:22

一、什么叫枚举数

enum Day(表示一个枚举)

{

    Sun,(表示一个枚举数),隐含的Sun的值为00表示枚举数的值

    Mon,

    Tue,

    Wed,

    Thu,

    Fri,

    Sat

};

 

枚举数是循环访问与之关联集合的对象,枚举数可被理解为指向集合中任何元素的可移动的指针。一个枚举数只能与一个集合管理,但一个集合可以具有多个枚举数。foreach语句使用枚举数来访问集合内元素,并且隐藏了枚举数中的复杂性。

 

二、什么叫迭代器

为了提供一个能从集合外部访问集合内部元素,而又不需要集合内部细节的功能,C#提供了foreach迭代功能,而配合foreach迭代功能的代码段,叫做迭代器。

迭代器的核心就是定义集合或者数组的枚举数,并公布之,让foreach能够访问。

 

·.迭代器是可以返回相同类型值的有序序列的一段代码(可以是循环语句,也可以不是);

·迭代器可用作方法、运算符或get访问器的代码体;

·迭代器代码使用yield return语句依次返回每个元素,yield break将终止迭代;

·可以在类中实现多个迭代器,每个迭代器都必须像任何类成员一样有惟一的名称,并且可以在foreach语句中被客户端代码调用;

·迭代器的返回类型必须为IEnumerableIEnumeratorIEnumerable (T) IEnumerator (T)中的任意一种;

·迭代器是产生值的有序序列的一个语句块,不同于有一个 或多个yield语句存在的常规语句块;

·迭代器不是一种成员,它只是实现函数成员的方式,理解这一点是很重要的,一个通过迭代器实现的成员,可以被其他可能或不可能通过迭代器实现的成员覆盖和重载;

·迭代器块在C#语法中不是独特的元素,它们在几个方面受到限制,并且主要作用在函数成员声明的语义上,它们在语法上只是语句块而已

 

三、IEnumerableIEnumeratorIEnumerable (T) IEnumerator (T)

//公布非泛型枚举数

public interface IEnumerable

{

      //IEnumerable只有一个方法,返回可循环访问集合的枚举数。

      IEnumerator GetEnumerator()  ;

}

 

//公布泛型枚举数

public interface IenumerableT

 

//定义非泛型枚举数

public interface IEnumerator

{ 

      // 方法

      //移到集合的下一个元素。如果成功则返回为 true;如果超过集合结尾,则返回false

      bool MoveNext();

 

     // 将集合设置为初始位置,该位置位于集合中第一个元素之前

      void Reset();

 

      // 属性:获取集合中的当前元素

      object Current { get; }

}

 

//定义泛型枚举数

public interface IenumeratorT

{ 

}

 

 

四、yield 关键字

foreach 语句对实现IEnumerable IEnumerable (T) 接口的数组或对象集合中的每个元素重复一组嵌入式语句。foreach 语句用于循环访问集合,以获取您需要的信息,但不能用于在源集合中添加或移除项,否则可能产生不可预知的副作用。如果需要在源集合中添加或移除项,请使用 for 循环。

嵌入语句为数组或集合中的每个元素继续执行。当为集合中的所有元素完成迭代后,控制传递给 foreach 块之后的下一个语句。

可以在 foreach 块的任何点使用 break 关键字跳出循环,或使用 continue 关键字进入循环的下一轮迭代。

foreach 循环还可以通过 gotoreturn throw 语句退出。

 

 

 

 

四、创建迭代器

最常用方法:

IEnumerable 接口实现 GetEnumerator 方法。

 

public System.Collections. IEnumerable  GetEnumerator()

{

    for (int i = 0; i < 10; i++)

    {

        yield return i;

    }

}

 

五、几种使用迭代器的方式

///////////////////////////////////////////////////////////////

using System;

using System.Collections ;

using System.Collections.Generic;

using System.Text;

 

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;

    }

 

    //我们的一个派生于IEnumerableIEnumerator接口的自定义类

    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;

        }

 

    }

}

 

 

//////////////////////////////////////////////////////////////////////////////////////////////

// Declare the collection:

public class SampleCollection

{

    public int[] items;

 

    public SampleCollection()

    {

        items = new int[5] { 5, 4, 7, 9, 3 };

    }

 

    public System.Collections.IEnumerable BuildCollection()

    {

        for (int i = 0; i < items.Length; i++)

        {

            yield return items[i];

        }

    }

}

 

class MainClass

{

    static void Main()

    {

        SampleCollection col = new SampleCollection();

 

        // Display the collection items:

        System.Console.WriteLine("Values in the collection are:");

        foreach (int i in col.BuildCollection())

        {

            System.Console.Write(i + " ");

        }

 

        // Keep the console window open in debug mode.

        System.Console.WriteLine("Press any key to exit.");

        System.Console.ReadKey();

    }

}

/* Output:

    Values in the collection are:

    5 4 7 9 3       

*/

 

////////////////////////////////////////////////////////////////////////////////////////////////

从下面的例子来分析IEnumeratorIenumerable之间的关系

using System;

using System.Collections;

//一个人

public class Person

{

    public Person(string fName, string lName)

    {

        this.firstName = fName;

        this.lastName = lName;

    }

 

    public string firstName;

    public string lastName;

}

//让列举的这些人可以被访问(IEnumerable动词形式)

public class People : IEnumerable

{

    private Person[] _people;

    public People(Person[] pArray)

    {

        _people = new Person[pArray.Length];

 

        for (int i = 0; i < pArray.Length; i++)

        {

            _people[i] = pArray[i];

        }

    }

 

    public IEnumerator GetEnumerator()

    {

        return new PeopleEnum(_people);

    }

}

//列举多个人(IEnumerator名词形式)

public class PeopleEnum : IEnumerator

{

    public Person[] _people;

 

    // Enumerators are positioned before the first element

    // until the first MoveNext() call.

    int position = -1;

 

    public PeopleEnum(Person[] list)

    {

        _people = list;

    }

 

    public bool MoveNext()

    {

        position++;

        return (position < _people.Length);

    }

 

    public void Reset()

    {

        position = -1;

    }

 

    public object Current

    {

        get

        {

            try

            {

                return _people[position];

            }

            catch (IndexOutOfRangeException)

            {

                throw new InvalidOperationException();

            }

        }

    }

}

 

class App

{

    static void Main()

    {

        Person[] peopleArray = new Person[3]

        {

            new Person("John", "Smith"),

            new Person("Jim", "Johnson"),

            new Person("Sue", "Rabon"),

        };

 

        People peopleList = new People(peopleArray);

        foreach (Person p in peopleList)

            Console.WriteLine(p.firstName + " " + p.lastName);

 

    }

}

 

/* This code produces output similar to the following:

 *

 * John Smith

 * Jim Johnson

 * Sue Rabon

 *

 */

 

 

 

六、特别注意

       C# 中,集合类不一定要从 IEnumerable IEnumerator 继承以便与 foreach 兼容。只要此类具有必需的 GetEnumeratorMoveNextReset Current 成员,就可 foreach 与一起使用。省略接口有一个好处:您可以将 Current 的返回类型定义得比 Object 更为明确,从而提供类型安全。

省略 IEnumerable IEnumerator 的缺点是,集合类不再能够与其他公共语言运行时兼容语言的 foreach 语句或等效项交互操作。

举例:

using System.Collections;

 

// Declare the Tokens class:

public class Tokens : IEnumerable

{

    private string[] elements;

 

    Tokens(string source, char[] delimiters)

    {

        // Parse the string into tokens:

        elements = source.Split(delimiters);

    }

 

    // IEnumerable Interface Implementation:

    //   Declaration of the GetEnumerator() method

    //   required by IEnumerable

    public IEnumerator GetEnumerator()

    {

        return new TokenEnumerator(this);

    }

 

 

    // Inner class implements IEnumerator interface:

    private class TokenEnumerator : IEnumerator

    {

        private int position = -1;

        private Tokens t;

 

        public TokenEnumerator(Tokens t)

        {

            this.t = t;

        }

 

        // Declare the MoveNext method required by IEnumerator:

        public bool MoveNext()

        {

            if (position < t.elements.Length - 1)

            {

                position++;

                return true;

            }

            else

            {

                return false;

            }

        }

 

        // Declare the Reset method required by IEnumerator:

        public void Reset()

        {

            position = -1;

        }

 

        // Declare the Current property required by IEnumerator:

        public object Current

        {

            get

            {

                return t.elements[position];

            }

        }

    }

 

 

    // Test Tokens, TokenEnumerator

    static void Main()

    {

        // Testing Tokens by breaking the string into tokens:

        Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

 

        foreach (string item in f)

        {

            System.Console.WriteLine(item);

        }

    }

}

/* Output:

    This

    is

    a

    sample

    sentence. 

*/

 

 

原创粉丝点击