zoukankan      html  css  js  c++  java
  • C# 迭代器与yield关键字

    迭代器模式是设计模式的一种,因为其运用的普遍性,很多语言都有内嵌的原生支持

    在.NET中,迭代器模式是通过IEnumeratorIEnumerable两个接口(有非泛型和泛型2种版本)来封装的

    迭代器模式的一个重要方面是:不是一次返回所有数据,而是每次调用只返回一个元素

    Array、IEnumerable和IEnumerator之间关系如下: 

    foreach遍历

    ① Array、集合容器类派生于IEnumerable接口类(该类中含有一个IEnumerator GetEnumerator()接口函数),Array、集合容器类实现了该函数,这使得foreach可对其进行遍历

        注:不需要从IEnumerable派生,只要类实现了IEnumerator GetEnumerator()函数,就可以使用foreach遍历该类中的元素

    ② IEnumerator定义了Current属性来返回游标所在的元素,MoveNext方法移动到下一个元素(若有元素则返回true,若到达末尾则返回false),Reset方法是将游标重置到第一项的位置

    int[] IntArray = new int[] { 1, 2, 3 };
    
    foreach (int n in IntArray)
    {
        Console.WriteLine(n);
    }
    
    // 上面的foreach等价于下方的代码实现
    IEnumerator e = IntArray.GetEnumerator();
    try
    {
        while (e.MoveNext())
        {
            Console.WriteLine((int)e.Current);
        }
    }
    finally
    {
        var disposable = e as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }

    在C#1.0中,创建IEnumerator枚举器需要写大量的代码。C#2.0添加了yield语句,让编译器自动创建IEnumerator枚举器。

    yield return语句返回集合的一个元素,并移动到下一个元素上。yield break可停止迭代。

    非泛型版本IEnumerator

    class EnumeratorTest
    {
        public IEnumerator GetEnumerator()
        {
            yield return 100;
            yield return "Good";
        }
    }
    
    EnumeratorTest eTest = new EnumeratorTest();
    foreach (object o in eTest)
    {
        Console.WriteLine(o);
    }

    编译后生成的代码如下:

    class EnumeratorTest
    {
        public IEnumerator GetEnumerator()
        {
            return new GenerateEnumerator(0);
        }
    
        private sealed class GenerateEnumerator : IEnumerator<object>, IEnumerator, IDisposable
        {
            // Fields
            private int  state;
            private object current;
    
            // Methods
            public GenerateEnumerator(int state)
            {
                this.state = state;
            }
    
            bool IEnumerator.MoveNext()
            {
                switch (this.state)
                {
                    case 0:
                        this.state = -1;
                        this.current = 100;
                        this.state = 1;
                        return true;
    
                    case 1:
                        this.state = -1;
                        this.current = "Good";
                        this.state = 2;
                        return true;
    
                    case 2:
                        this.state = -1;
                        break;
                }
                return false;
            }
    
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }
    
            void IDisposable.Dispose()
            {
            }
    
            // Properties
            object IEnumerator<object>.Current
            {
                get
                {
                    return this.current;
                }
            }
            object IEnumerator.Current
            {
                get
                {
                    return this.current;
                }
            }
        }
    }
    
    EnumeratorTest eTest = new EnumeratorTest();
    IEnumerator e = eTest.GetEnumerator();
    try
    {
        while (e.MoveNext())
        {
            Console.WriteLine(e.Current);
        }
    }
    finally
    {
        var disposable = e as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }

    泛型版本IEnumerator<T>

    class EnumeratorTest2
    {
        private bool m_bBreak;
    
        public EnumeratorTest2(bool bBreak)
        {
            m_bBreak = bBreak;
        }
    
        public IEnumerator<string> GetEnumerator()
        {
            yield return "Hello";
            if (m_bBreak)
            {
                yield break;
            }
            yield return "World";
        }
    }
    
    EnumeratorTest2 eTest2 = new EnumeratorTest2(true);
    IEnumerator<string> e2 = eTest2.GetEnumerator();
    while (e2.MoveNext())
    {
        Console.WriteLine(e2.Current);
    }

    编译后生成的代码如下:

    class EnumeratorTest2
    {
        private bool m_bBreak;
    
        public EnumeratorTest2(bool bBreak)
        {
            m_bBreak = bBreak;
        }
    
        public IEnumerator<string> GetEnumerator()
        {
            GenerateEnumerator2 e2 = new GenerateEnumerator2(0);
            e2.eTest2 = this;
            return e2;
        }
    
        private sealed class GenerateEnumerator2 : IEnumerator<string>, IEnumerator, IDisposable
        {
            // Fields
            private int state;
            private string current;
    
            public EnumeratorTest2 eTest2;
    
            // Methods
            public GenerateEnumerator2(int state)
            {
                this.state = state;
            }
    
            bool IEnumerator.MoveNext()
            {
                switch (this.state)
                {
                    case 0:
                        this.state = -1;
                        this.current = "Hello";
                        this.state = 1;
                        return true;
    
                    case 1:
                        this.state = -1;
                        if (eTest2.m_bBreak)
                        {
                            break;
                        }
                        this.current = "World";
                        this.state = 2;
                        return true;
    
                    case 2:
                        this.state = -1;
                        break;
                }
                return false;
            }
    
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }
    
            void IDisposable.Dispose()
            {
            }
    
            // Properties
            string IEnumerator<string>.Current
            {
                get
                {
                    return this.current;
                }
            }
            object IEnumerator.Current
            {
                get
                {
                    return this.current;
                }
            }
        }
    }
    
    EnumeratorTest2 eTest2 = new EnumeratorTest2(true);
    IEnumerator<string> e2 = eTest2.GetEnumerator();
    while (e2.MoveNext())
    {
        Console.WriteLine(e2.Current);
    }

    非泛型版本IEnumerable

    class EnumeratorTest3
    {
        public IEnumerable Test1()
        {
            yield return 100;
            yield return 200;
        }
    }
    
    EnumeratorTest3 eTest3 = new EnumeratorTest3();
    foreach (object o in eTest3.Test1())
    {
        Console.WriteLine(o);
    }

    编译后生成的代码如下:

    class EnumeratorTest3
    {
        public IEnumerable Test1()
        {
            return new GenerateEnumerable3(0);
        }
    
        private sealed class GenerateEnumerable3 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
        {
            // Fields
            private int state;
            private int current;
    
            // Methods
            public GenerateEnumerable3(int state)
            {
                this.state = state;
            }
    
            bool IEnumerator.MoveNext()
            {
                switch (this.state)
                {
                    case 0:
                        this.state = -1;
                        this.current = 100;
                        this.state = 1;
                        return true;
    
                    case 1:
                        this.state = -1;
                        this.current = 200;
                        this.state = 2;
                        return true;
    
                    case 2:
                        this.state = -1;
                        break;
                }
                return false;
            }
    
            IEnumerator<object> IEnumerable<object>.GetEnumerator()
            {
                return this;
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this;
            }
    
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }
    
            void IDisposable.Dispose()
            {
            }
    
            // Properties            
            object IEnumerator<object>.Current
            {
                get
                {
                    return this.current;
                }
            }
            object IEnumerator.Current
            {
                get
                {
                    return this.current;
                }
            }
        }
    }
    
    EnumeratorTest3 eTest3 = new EnumeratorTest3();
    IEnumerator e3 = eTest3.Test1().GetEnumerator();
    while (e3.MoveNext())
    {
        Console.WriteLine(e3.Current);
    }

    泛型版本IEnumerable<T>

    class EnumeratorTest4
    {
        private bool m_bBreak;
    
        public EnumeratorTest4(bool bBreak)
        {
            m_bBreak = bBreak;
        }
    
        public IEnumerable<float> Test1()
        {
            yield return 1.0f;
            if (m_bBreak)
            {
                yield break;
            }
            yield return 3.0f;
        }
    }
    
    EnumeratorTest4 eTest4 = new EnumeratorTest4(true);
    foreach (object o in eTest4.Test1())
    {
        Console.WriteLine(o);
    }

    编译后生成的代码如下: 

    class EnumeratorTest4
    {
        private bool m_bBreak;
    
        public EnumeratorTest4(bool bBreak)
        {
            m_bBreak = bBreak;
        }
    
        public IEnumerable<float> Test1()
        {
            GenerateEnumerable4 e4 = new GenerateEnumerable4(0);
            e4.eTest4 = this;
            return e4;
        }
    
        private sealed class GenerateEnumerable4 : IEnumerable<float>, IEnumerable, IEnumerator<float>, IEnumerator, IDisposable
        {
            // Fields
            private int state;
            private float current;
    
            public EnumeratorTest4 eTest4;
    
            // Methods
            public GenerateEnumerable4(int state)
            {
                this.state = state;
            }
    
            bool IEnumerator.MoveNext()
            {
                switch (this.state)
                {
                    case 0:
                        this.state = -1;
                        this.current = 1.0f;
                        this.state = 1;
                        return true;
    
                    case 1:
                        this.state = -1;
                        if (this.eTest4.m_bBreak)
                        {
                            break;
                        }
                        this.current = 3.0f;
                        this.state = 2;
                        return true;
    
                    case 2:
                        this.state = -1;
                        break;
                }
                return false;
            }
    
            IEnumerator<float> IEnumerable<float>.GetEnumerator()
            {
                return this;
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this;
            }
    
            void IEnumerator.Reset()
            {
                throw new NotSupportedException();
            }
    
            void IDisposable.Dispose()
            {
            }
    
            // Properties            
            float IEnumerator<float>.Current
            {
                get
                {
                    return this.current;
                }
            }
            object IEnumerator.Current
            {
                get
                {
                    return this.current;
                }
            }
        }
    }
    
    EnumeratorTest4 eTest4 = new EnumeratorTest4(true);
    IEnumerator<float> e4 = eTest4.Test1().GetEnumerator();
    while (e4.MoveNext())
    {
        Console.WriteLine(e4.Current);
    }

  • 相关阅读:
    acwing2-01背包问题
    背包问题(转载)
    考研易错点 二叉树的度和图的度
    考研易错点*s++
    考研复习易错点数组指针和指针数组
    Android Crash Learning
    Mysql5.7中的分组排序
    康师傅JVM:StringTable(十三)
    RocketMQ集群搭建
    RocketMq的单机安装
  • 原文地址:https://www.cnblogs.com/kekec/p/11269285.html
Copyright © 2011-2022 走看看