zoukankan      html  css  js  c++  java
  • foreach yield (转)

    在C#中,foreach的使用简化了很多循环语法的书写。如果初学者仅仅把foreach当成for循环的省略写法的话,就显得有点大才小用了。事实上,foreach与“迭代”和“枚举”密切相关。

    C#编译器会把foreach语句转换为IEnumerable接口的方法和属性。例如:

                foreach (Person p in persons)
                {
    Console.WriteLine(p);
                }

    以上代码迭代persons数组中的所有元素,并逐个显示他们。

    foreach语句会解析成下面的代码。首先调用GetEnumerator()方法,获得数组的一个枚举。在while循环中(只要MoveNext()返回true),用Current属性访问数组中的元素:

                IEnumerator enumerator = persons.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    Person p = (Person) enumerator.Current;
    Console.WriteLine(p);
                }

    这里要说明的是。用[]声明数组是C#中使用Array类的记号。Array类实现了IEnumerable接口中的GetEnumerator()方法。使用foreach语句迭代数组,其实是使用了Array类中个GetEnumerator()方法。

    也就是说,只要是实现了IEnumerable接口中的GetEnumerator()方法的类,都可以用foreach语句来迭代。

    IEnumerable接口中的GetEnumerator()方法是这样定义的:

    IEnumerator GetEnumerator()

    其返回的类型是一个IEnumerator接口。

    IEnumerator接口中的Current属性返回光标所在的元素。

    IEnumerator接口中的MoveNext()方法移动到集合的下一个元素上,如果有这个元素,该方法就返回true。如果集合不再有更多的元素,该方法就返回false。

    IEnumerator接口中的Reset()方法将光标重新定位于集合的开头。许多枚举会抛出NotSupportedException异常。

    下面,我们来写一个实现了IEnumerable接口的类。

                        public class HelloCollection:IEnumerable
                        {
                            public IEnumerator GetEnumerator()
                            {
                                yield return "Hello";
                                yield return "World";
                            }
                        }

    现在可以用foreach语句迭代了:

            static void Main(string[] args)
            {

                HelloCollection helloCollection=new HelloCollection ();
                foreach (string s in helloCollection )
                {
                    Console.WriteLine(s);
                }
            }

    实际上,yield return语句返回集合的一个元素,并移动到下一个元素上。它会将类HelloCollection解析成如下代码:

            public class HelloCollection : IEnumerable
            {
                public IEnumerator GetEnumerator()
                {
                    Enumertor enumerator = new Enumerator();
                    return enumerator;
                }

                public class Enumertor : IEnumerator, IDisposable
                {
                    private int state;
                    private object current;

                    public Enumertor(int state)
                    {
                        this.state = state;
                    }
                }
                    bool System.Collections .IEnumerator .MoveNext()
                    {
                        switch (state)
                        {
                            case 0:
                                current = "Hello";
                                state = 1;
                                return true;
                            case 1:
                                current = "World";
                                state = 2;
                                return true ;
                            case 2:
                                break ;
                        }
                        return false ;
                    }

                    void System.Collections .IEnumerator .Reset()
                    {
                        throw new NotSupportedException();
                    }

                    object System.Collections .IEnumerator .Current
                    {
                        get { return current; }
                    }
                    void IDisposable.Dispose()
                    {
                    }
            }

    foreach语句默认用GetEnumerator()方法迭代,也可以自行制定迭代方法。举例:

            public class MusicTitles:IEnumerable
            {
                string[] names = { "Tubular Bells", "Hergest Ridge", "Ommadawn", "Platinum" };

                public IEnumerator GetEnumerator()  /*顺序迭代*/
                {
                    for (int i = 0; i < 4; i++)
                        yield return names[i];
                }

                public IEnumerator Reverse()  /*逆序迭代*/
                {
                    for (int i = 3; i >= 0; i--)
                        yield return names[i];
                }
            }

    在foreach语句中不必写明使用GetEnumerator()方法迭代,因为这是默认方法。如下:

            static void Main(string[] args)
            {

                MusicTitles titles = new MusicTitles();
                foreach (string title in titles)
                {
                    Console.WriteLine(title);
                }

                Console.WriteLine();

                foreach (string title in titles.Reverse())
                {
                    Console.WriteLine(title);
                }
            }

  • 相关阅读:
    OAuth认证介绍及腾讯微博OAuth认证示例
    Android PopupWindow介绍及实现菜单效果
    Android 输入法键盘和activity页面遮挡问题解决
    eclipse中android项目的编译过程分析
    Android Tween动画之RotateAnimation实现图片不停旋转
    eclipse 文件同步插件
    关于移动Web应用程序开发 HTML5、高性能JavaScript篇、Css的几篇较好博客
    Android 记录和恢复ListView滚动的位置的三种方法
    Apache的功能模块
    如何防止自己网站的图片被其他网站所盗用,从而导致自己网站流量的损失【apache篇】
  • 原文地址:https://www.cnblogs.com/axyz/p/1886927.html
Copyright © 2011-2022 走看看