黑马程序员 枚举数和迭代器 总结

原创 2013年12月05日 20:08:54
---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

1.为什么数组可以使用foreach遍历。原因是数组可以按需提供一个叫做枚举数的对象。枚举数可以依次返回请求的数组元素。
我的话说就是:数组实现了一个叫IEnumerable的接口,该接口有一个方法GetEnumerator(); 该方法返回一个实现了IEnumerator接口的对象,利用该对象可以依次取出这个数组的每个值。

2.foreach 结构被设计用来和可枚举类型一起使用。只要给它的遍历对象是可枚举类型,比如数组,它就会执行如下行为:通过调用GetEnumerator方法获取对象的枚举数;
从枚举数中请求每一项把它作为迭代变量,代码可以读但不可以改变。

3.IEnumerator接口
IEnumerator接口包含3个函数成员:Current、MoveNext、以及Reset
Current返回序列中当前位置项的属性。
MoveNext是把枚举位置前进到集合中下一项的方法。它也返回布尔值,指示新的位置是有效位置或已经超过了序列的尾部。

4.IEnumerable接口只有一个成员——GetEnumerator方法,它返回对象的枚举数。

5.我们来看一个自己实现枚举数的例子:
    class ColorEnumerator : IEnumerator
    {
        string[] Colors;
        int Position = -1;

        public ColorEnumerator(string[] theColors)
        {
            Colors = new string[theColors.Length];
            for (int i = 0; i < theColors.Length; i++)
            {
                Colors[i] = theColors[i];
            }

        }

        public object Current
        {
            get
            {
                if(Position == -1 || Position == Colors.Length)
                throw new NotImplementedException();
                return Colors[Position];
            }
        }

        public bool MoveNext()
        {
            if (Position < Colors.Length - 1)
            {
                Position++;
                return true;
            }
            else
                return false;
        }

        public void Reset()
        {
            Position = -1;
        }
    }

    class MyColors : IEnumerable
    {
        string[] Colors = { "Red","Yellow","Blue"};

        public IEnumerator GetEnumerator()
        {
            return new ColorEnumerator(Colors);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyColors mc = new MyColors();
            foreach (string color in mc)
            {
                Console.WriteLine(color);
            }

            Console.ReadKey();
        }
    }

6.IEnumerator<T>接口
IEnumerator<T>接口使用泛型来返回实际的类型,而不是Object类型的引用。
IEnumerator<T>接口从另外两个接口继承——非泛型IEnumerator接口和IDisposable接口。实现成员:
IDisposable 接口只有一个叫做Dispose的类型为void的无参方法,它可以用来释放由类占据的非托管资源
IEnumerator<T>接口本身只有一个Current特性,它返回类型T或它衍生的项的实例——不是ojbect类型的引用。
由于IEnumerator<T>和IEnumerator都有一个叫做Current的成员,我们应该显式实现IEnumerator版本,然后在类中实现泛型版本。

7.IEnumerable<T>接口
泛型版本从IEnumerator继承,所以也必须实现IEnumerable接口
与IEnumerable差不多,泛型版本也包含了一个方法——GetEnumertor。然而,这个版本的GetEnumerator实现泛型IEnumerator<T>接口的类对象。
由于类必须实现两个GetEnumerator方法,我们需要显式实现非泛型版本,并在类中实现泛型版本。

8.用泛型接口实现的迭代器,示例:
    class ColorEnumerator : IEnumerator<string>
    {
        string[] Colors;
        int Position = -1;

        public ColorEnumerator(string[] theColors)
        {
            Colors = new string[theColors.Length];
            for (int i = 0; i < theColors.Length; i++)
            {
                Colors[i] = theColors[i];
            }

        }

        object IEnumerator.Current
        {
            get
            {
                if(Position == -1 || Position == Colors.Length)
                throw new NotImplementedException();
                return Colors[Position];
            }
        }

        public bool MoveNext()
        {
            if (Position < Colors.Length - 1)
            {
                Position++;
                return true;
            }
            else
                return false;
        }

        public void Reset()
        {
            Position = -1;
        }

        public void Dispose()
        {
            //throw new NotImplementedException();
        }

        public string  Current
        {
            get
            {
                if (Position == -1 || Position == Colors.Length)
                    throw new NotImplementedException();
                return Colors[Position];
            }
        }
    }

    class MyColors : IEnumerable<string>
    {
        string[] Colors = { "Red","Yellow","Blue"};

        public IEnumerator<string> GetEnumerator()
        {
            return new ColorEnumerator(Colors);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new ColorEnumerator(Colors);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyColors mc = new MyColors();
            foreach (string color in mc)
            {
                Console.WriteLine(color);
            }

            Console.ReadKey();
        }
    }

9.迭代器:
迭代器就是为我们简化创建迭代数的东西,我们不用再外写一个实现IEnumerator接口的枚举器了,现在只要在我们的类中简单写一个方法可以返回IEnumerator类型(使用yield return 这叫迭代器),再实现IEnumerable接口, GetEnumerator方法中调迭代器就可。 实际上,这是编译器帮我们简化了,再编译时编译器还是创建了枚举器。
 
迭代器示例:
    class Myclass
    {

        public IEnumerator<string> GetEnumerator()
        {
           return BlackAndWhite();
        }

        public IEnumerator<string> BlackAndWhite()
        {
            yield return "black";
            yield return "glay";
            yield return "white";
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            Myclass myC = new Myclass();

            foreach (string str in myC)
            {
                Console.WriteLine(str);
            }

            Console.ReadKey();
        }
    }
其实foreach迭代时,那个类只需有GetEnumerator方法(public 无参)就行,所以自己创建枚举器时,类名后也可以不加 : IEnumerable。   还可以使用迭代器来创建可枚举类型,BlackAndWhite还可以返回IEnumerable<string>,等各种玩法。在foreach中还可以直接调用BlackAndWhite方法,因为它返回的是可枚举类型,如下:
    class Myclass
    {

        public IEnumerator<string> GetEnumerator()
        {
            return BlackAndWhite().GetEnumerator();
        }

        public IEnumerable<string> BlackAndWhite()
        {
            yield return "black";
            yield return "glay";
            yield return "white";
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            Myclass myC = new Myclass();

            foreach (string str in myC)
            {
                Console.WriteLine(str);
            }

            foreach (string str in myC.BlackAndWhite())
            {
                Console.WriteLine(str);
            }

            Console.ReadKey();
        }
    }
比较两种迭代模式:
1.如果实现GetEnumerator,它调用迭代器方法以获取自动生成的实现IEnumerable的类实例。然后,从IEnumerator对象返回由GetEnumerable对象返回由GetEumerator创建的枚举数。
2.如果通过不实现GetEnumerator使类本身不可被枚举,仍然可以使用由迭代器返回的可枚举类,只需要直接调用迭代器方法。
我们可使用第2种模式不实现GetEnumerator,直接调用迭代器方法可以写多个可枚举类型。
还可以使用属性产生多个枚举数:
{
    class Myclass :IEnumerable<string>
    {
        bool ColorFlag = false;

        public Myclass(bool flag)
        {
            ColorFlag = flag;
        }

        IEnumerator<string> BlackAndWhite
        {
            get
            {
                yield return "black";
                yield return "glay";
                yield return "white";
            }
        }

        IEnumerator<string> Colors
        {
            get
            {
                string[] theColors = { "blue", "red", "yellow"};
                for(int i=0;i<theColors.Length;i++)
                    yield return theColors[i];
            }
        }

        public IEnumerator<string> GetEnumerator()
        {
            return ColorFlag
                ? Colors
                : BlackAndWhite;
        }


        IEnumerator IEnumerable.GetEnumerator()  //IEnumerator需要引用命名空间System.Collections;
        {
            return ColorFlag
                ? Colors
                : BlackAndWhite;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Myclass myC = new Myclass(true);

            foreach (string str in myC)
            {
                Console.WriteLine(str);
            }

            Console.ReadKey();
        }
    }

10.迭代器实质
由编译器生成的枚举数类是有4个状态的状态机。
Before 首次调用MoveNext的初始状态
Running 调用MoveNext后时入这个状态。在这个状态中,枚举数检测并设置下一项的位置,在遇到yield rturn 、yield brdak或在迭代器体结束时,退出状态。
Suspended 状态机等待下次调用MoveNext的状态。
After 没有更多项可以枚举

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

枚举器和迭代器(一)

 C#中的枚举器(enumerator)通俗的讲是一个可以递进式的访问一个序列的指针(可能这并不恰当)。foreach语句(迭代语句)是我们比较熟悉的,例如顺序输入一个字符串中的每个字符:foreac...
  • loveyou128144
  • loveyou128144
  • 2009年11月10日 22:18
  • 4957

20. 枚举数和迭代器

20.1 枚举数和可枚举类型
  • manofstyle1
  • manofstyle1
  • 2014年09月14日 21:15
  • 463

枚举器和迭代器之间的区别?

区别:Enumerator与Iterator你的java面试。在这篇文章中,我列出了在回答问题时可能引用的几个差异。 枚举器和迭代器之间的区别 首先,枚举仅适用于传统类,例如Has...
  • qq496013218
  • qq496013218
  • 2017年07月11日 15:56
  • 875

C# 入门(14) 枚举器(enumerator)和迭代器(iterator)

C#的枚举器和迭代器
  • l773575310
  • l773575310
  • 2017年05月04日 10:50
  • 336

黑马程序员12——枚举数和迭代器

---------------------- Windows Phone 7手机开发、.Net培训、 期待与您交流!---------------------- 为什么foreach可以...
  • hm_liujunhong
  • hm_liujunhong
  • 2012年10月05日 17:08
  • 333

C# 枚举数和迭代器总结

1.为什么数组可以使用foreach遍历。原因是数组可以按需提供一个叫做枚举数的对象。枚举数可以依次返回请求的数组元素。 我的话说就是:数组实现了一个叫IEnumerable的接口,该接口有一个方法...
  • natsu1211
  • natsu1211
  • 2014年10月08日 01:48
  • 1135

黑马程序员--一段给后者的面试总结

文章来源:黑马程序员, 北京之旅,行北京万事,通百姓生活。其实,我也是个农村出来的孩子,大学没毕业就来北京参加“黑马”,毕业之后,还是没有任何的机遇与机会让我能在那里一展雄威,这就是我们这些菜鸟的悲...
  • heima_hb6
  • heima_hb6
  • 2014年08月24日 13:51
  • 558

Java集合之枚举和迭代

在java集合中顶层有这样两个接口Iterator和Enumeration,这两个接口是特殊的数据操作接口。Iterator用于进行数据迭代,称为迭代器;Enumeration用于进行数据枚举,称为枚...
  • Calvex880714
  • Calvex880714
  • 2013年04月06日 15:44
  • 4569

关于迭代器的一些总结

python中迭代器
  • kellyseeme
  • kellyseeme
  • 2016年04月03日 21:06
  • 344

Iterator迭代器-ListIterator-Enumeration枚举类接口的特点和区别

Iterator迭代器-ListIterator-Enumeration枚举类接口的特点和区别 1、Iterator的特点:     API中是这样解释的: 对collection进行迭代的迭代器。它...
  • u014344668
  • u014344668
  • 2015年04月25日 11:22
  • 1465
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:黑马程序员 枚举数和迭代器 总结
举报原因:
原因补充:

(最多只允许输入30个字)