打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C#中的迭代器(详解yield)

迭代器设计模式举例:

namespace YieldSample01

{

    public class HelloCollection: IEnumerable

    {

        public IEnumerator GetEnumerator()

        {

            returnnew Enumerator(-1);

        }

        public class Enumerator :IEnumerator

        {

            privateint _state;

            publicobject Current { get;private set; }

            publicEnumerator(int state)

            {

                _state = state;

            }

            publicbool MoveNext()

            {

                _state++;

                switch(_state)

                {

                    case0:

                        Current = "Hello";

                        returntrue;

                    case1:

                        Current = "World";

                        return true;

                    default:

                        return false;

                }

            }

            publicvoid Reset()

            {

                _state = -1;

            }

        }

    }

}

namespace YieldSample01

{

    class Program

    {

        static void Main(string[]args)

        {

            HelloCollectionhelloCollection = new HelloCollection();

            foreach(string s inhelloCollection)

            {

                Console.WriteLine(s);

            }

        }

    }

}

可枚举类型和可枚举数在.NET集合类中广泛使用,所以知道它们如何工作很重要。但是,既然我们已经知道如何创建自己的可枚举类以及枚举数了,我们可能会很高兴听到,C#2.0版本开始提供了更简单的创建枚举数和可枚举类型的方式。其实,编译器会为我们创建它们。这种结构叫做迭代器。我们可以把手动编码的可枚举类型和枚举数替换为由迭代器生成的可枚举类型和枚举数。

C#迭代器举例:

namespace YieldSample02

{

    public class HelloCollection:IEnumerable

    {

        public IEnumerator GetEnumerator()

        {

            yieldreturn "Hello";

            yieldreturn "World";

        }

    }

}

namespace YieldSample02

{

    class Program

    {

        static void Main(string[]args)

        {

            HelloCollectionhelloCollection = new HelloCollection();

            foreach(string s inhelloCollection)

            {

                Console.WriteLine(s);

            }

        }

    }

}

【迭代器块】

迭代器块是一个或多个yield语句的代码块。

迭代器块被认为与其他代码块不同。其他块包含的语句被当作是命令式的。也就是说,代码块的第一个语句被执行然后是后面的语句,最后控制离开块。

然而,迭代器块不是需要在同一时间执行的一序列命令式命令,而是描述了希望编译器为我们创建的枚举数的行为(编译器生成一个类来实现迭代器块中表示的行为)。迭代器块中的代码描述了如何枚举元素。

迭代器块有两个特殊语句:

yield return <expression> 语句返回集合的一个元素,并移动到下一个元素上。

yield break 语句停止迭代。

例子一:

namespace YieldSample03

{

    publicclass A : IEnumerable<int>

    {

        privatereadonly int[]_array = new int[10];

        publicA()

        {

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

            {

                _array[i] = i;

            }

        }

        publicIEnumerator<int>GetEnumerator()

        {

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

            {

                yield return_array[i];

            }

        }

        IEnumeratorIEnumerable.GetEnumerator()

        {

            returnGetEnumerator();

        }

    }

}

namespace YieldSample03

{

    classProgram

    {

        staticvoid Main(string[]args)

        {

            Aa = new A();

            foreach(int i in a)

            {

                Console.WriteLine(i);

            }

        }

    }

}

例子二:

namespace YieldSample04

{

    publicclass A : IEnumerable<int>

    {

        privatereadonly int[]_array = new int[10];

        publicA()

        {

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

            {

                _array[i] = i;

            }

        }

        publicIEnumerator<int>GetEnumerator()

        {

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

            {

                if (i < 8)

                {

                    yield return_array[i];

                }

                else

                {

                    yield break;

                }

            }

        }

        IEnumeratorIEnumerable.GetEnumerator()

        {

            returnGetEnumerator();

        }

    }

}

namespace YieldSample04

{

    classProgram

    {

        staticvoid Main(string[]args)

        {

            Aa = new A();

            foreach(int i in a)

            {

                Console.WriteLine(i);

            }

        }

    }

}

例子三:

namespace YieldSample05

{

    public class MyClass:IEnumerable<string>

    {

        public IEnumerator<string>GetEnumerator()

        {

            yieldreturn "black";

            yieldreturn "gray";

            yieldreturn "white";

        }

        IEnumeratorIEnumerable.GetEnumerator()

        {

            returnGetEnumerator();

        }

    }

}

namespace YieldSample05

{

    class Program

    {

        static void Main(string[]args)

        {

            MyClassmc = new MyClass();

            foreach(string shade inmc)

            {

                Console.WriteLine(shade);

            }

        }

    }

}

例子四:

namespace YieldSample06

{

    public class MyClass:IEnumerable<string>

    {

        privatereadonly bool_colorFlag = true;

        publicMyClass(bool flag)

        {

            _colorFlag = flag;

        }

        privateIEnumerator<string>BalckAndWhite

        {

            get

            {

                yieldreturn "black";

                yieldreturn "gray";

                yieldreturn "white";

            }

        }

        privateIEnumerator<string>Colors

        {

            get

            {

                string[]theColors = {"blue","red","yellow"};

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

                    yieldreturn theColors[i];

            }

        }

        public IEnumerator<string>GetEnumerator()

        {

            return_colorFlag ? BalckAndWhite : Colors;

        }

        IEnumeratorIEnumerable.GetEnumerator()

        {

            returnGetEnumerator();

        }

    }

}

namespace YieldSample06

{

    internal class Program

    {

        privatestatic voidMain(string[] args)

        {

            MyClassmc1 = new MyClass(true);

            foreach(string s inmc1)

            {

                Console.WriteLine(s);

            }

            Console.WriteLine("--------");

            MyClassmc2 = new MyClass(false);

            foreach(string s inmc2)

            {

                Console.WriteLine(s);

            }

            Console.WriteLine("--------");

           IEnumerator<string> enu = mc2.GetEnumerator();

            //enu.Reset();//抛异常

            while(enu.MoveNext())

            {

                Console.WriteLine(enu.Current);

            }

        }

    }

}

【迭代器实质】

迭代器需要System.Collection.Generic命名空间,因此我们需要使用using指令包含它。

在编译器生成的枚举数中,Reset方法没有实现。而它是接口需要的方法,因此调用实现时总是抛出System.NotSupportedException异常。

在后台,由编译器生成的枚举数是有4个状态的状态机。

Before:首次调用MoveNext的初始状态。

Running:调用MoveNext后进入这个状态。在这个状态中,枚举数检测并设置下一项的位置。在遇到yield returnyieldbreak或在迭代器体结束时,退出状态。

Suspended:状态机等待下一次调用MoveNext的状态。

After:没有更多可以枚举。

如果状态机在BeforeSuspended状态,并且有一次MoveNext方法调用,它就转到了Running状态。在Running状态中,它检测集合的下一项并设置位置。

如果有更多项,状态机会转入Suspended状态,如果没有更多项,它转入并保持在After状态。



通过微信学习的知识只能是碎片化的知识,作为新时代的我们希望能够构建自己的知识结构,使我们的知识体系化,系统化,以后在遇到碎片化的知识,我们做的只是融合到自己的知识结构中,故我们将推出“与LSGO一起学”系列课程,帮助大家来构建知识框架,初步规划有:

  1. “与LSGO一起学C++”;

  2. “与LSGO一起学C#”;

  3. LSGO一起学Matlab”;

  4. “与LSGO一起学数据结构”;

  5. “与LSGO一起学设计模式”;

  6. “与LSGO一起学可视化建模语言(UML)”;

  7. “与LSGO一起学线性代数”;

  8. “与LSGO一起学高等数学”

  9. “与LSGO一起学概率论与数理统计”;

  10. “与LSGO一起学抽象代数;

  11. “与LSGO一起学点集拓扑”

  12. “与LSGO一起学数字图像处理”;

  13. “与LSGO一起学智能计算”;

如果对这些内容感兴趣,可以一起来学习讨论。

我们的官网: www.lsgogroup.com

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C#中要使一个类支持FOREACH遍历,实现过程怎样?
.NET设计模式(18):迭代器模式(Iterator Pattern)
C#中foreach语句的迭代器实现机制
什么是迭代器,创建并使用迭代器.为整数列表创建迭代器.为泛型列表创建迭代器 - さびしい....
迭代器的使用
一文说通C#中的异步迭代器
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服