• 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);
                }
            }

  • 相关阅读:
    CentOS8配置
    粘包和拆包
    基于.NET的程序读取Excel文件的解决方案
    T-SQL——基础语法
    备忘录:SQL SERVER2014 出现:“Cannot find one or more components”
    .NET CORE命令行
    备忘录:默认开机展示大屏页面
    微信小程序--投票小程序设计与实现(图片、视频发布、分组、审核、排名 全开源)
    PicGo RequestError: Error: tunneling socket could not be established, cause=connect ECONNREFUSED 127.0.0.1:36677
    Failed to convert value of type 'java.lang.String' to required type
  • 原文地址:https://www.cnblogs.com/axyz/p/1873706.html
Copyright © 2020-2023  润新知