zoukankan      html  css  js  c++  java
  • yield 关键字和迭代器

    一般使用方法
     
     
    yield 关键字向编译器指示它所在的方法是迭代器块
    在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值。 这是一个返回值,例如,在
    foreach 语句的每一次循环中返回的值。 yield 关键字也可与 break 结合使用,表示迭代结束。
     
    不允许不安全块。
     
    方法、运算符或访问器的参数不能是 ref 或 out。
     
    yield return 语句不能放在 try-catch 块中的任何位置。 该语句可放在后跟 finally 块的 try 块中。
     
    yield break 语句可放在 try 块或 catch 块中,但不能放在 finally 块中。
    yield 语句不能出现在匿名方法中
     
    Yield的执行方法
    调用函数
    调用者请求item
    下一个item返回
    回到步骤2
     
     
    yield不能单独放在try-catch块中,如果try中有yield那么,这个try块后面不许跟着finally块;也不能出现在匿名
    方法中,所以,看起来yield似乎并不常用,但是也不是不用。我前面有一个关于迭代器的例子《C#中的迭代器基础
    》中就用到了。可以参考一下那个例子,但是这里要再说的一点是我后来看到的,yield是跟return一起使用的,形
    式为yield return xxx,一般来说单独的return在每个方法中只能存在一个。而yield则不同的是,可以出现连续多
    个。
    迭代器,是一个连续的集合,出现多个yield return其实就是将这多个的yield return元素按照出现的顺序存储在迭
    代器的集合中而已
    static IEnumerable<Int32> CountWithTimeLimit(DateTime limit)
    {
        try
        {
            for (int i = 1; i <= 100; i++)
            {
                if (DateTime.Now >= limit)
                {
                    yield break;
                }
                yield return i;
            }
        }
        finally
        {
            Console.WriteLine("停止迭代!"); Console.ReadKey();
        }
    }
    static void Main(string[] args)
    {
        DateTime stop = DateTime.Now.AddSeconds(2);
        foreach (Int32 i in CountWithTimeLimit(stop))
        {
            Console.WriteLine("返回 {0}", i);
            Thread.Sleep(300);
        }
    }
     
    简单几行代码就能够完全实现IterationSampleIterator类所需要的功能。方法看起来很普通,除了使用了yield
    return。这条语句告诉编译器这不是一个普通的方法,而是一个需要执行的迭代块(yield block),他返回一个
    IEnumerator对象,你能够使用迭代块来执行迭代方法并返回一个IEnumerable需要实现的类型,IEnumerator或者对
    应的泛型。如果实现的是非泛型版本的接口,迭代块返的yield type是Object类型,否则返回的是相应的泛型类型。
    例如,如果方法实现IEnumerable<String>接口,那么yield返回的类型就是String类型。 在迭代块中除了yield
    return外,不允许出现普通的return语句。块中的所有yield return 语句必须返回和块的最后返回类型兼容的类型
    。举个例子,如果方法定义需要返回IEnumeratble<String>类型的话,不能yield return 1 。 需要强调的一点是,
    对于迭代块,虽然我们写的方法看起来像是在顺序执行,实际上我们是让编译器来为我们创建了一个状态机。这就是
    在C#1中我们书写的那部分代码---调用者每次调用只需要返回一个值,因此我们需要记住最后一次返回值时,在集合
    中位置。 当编译器遇到迭代块是,它创建了一个实现了状态机的内部类。这个类记住了我们迭代器的准确当前位置
    以及本地变量,包括参数。这个类有点类似与我们之前手写的那段代码,他将所有需要记录的状态保存为实例变量。
    下面来看看,为了实现一个迭代器,这个状态机需要按顺序执行的操作:
     
    它需要一些初始的状态
    当MoveNext被调用时,他需要执行GetEnumerator方法中的代码来准备下一个待返回的数据。
    当调用Current属性是,需要返回yielded的值。
    需要知道什么时候迭代结束是,MoveNext会返回false
     
    class Program
    {
        static readonly String Padding = new String(' ', 30);
        static IEnumerable<Int32> CreateEnumerable()
        {
            Console.WriteLine("{0} CreateEnumerable()方法开始", Padding);
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("{0}开始 yield {1}", i);
                yield return i;
                Console.WriteLine("{0}yield 结束", Padding);
            }
            Console.WriteLine("{0} Yielding最后一个值", Padding);
            yield return -1;
            Console.WriteLine("{0} CreateEnumerable()方法结束", Padding);
        }
     
        static void Main(string[] args)
        {
            IEnumerable<Int32> iterable = CreateEnumerable();
            IEnumerator<Int32> iterator = iterable.GetEnumerator();
            Console.WriteLine("开始迭代");
            while (true)
            {
                Console.WriteLine("调用MoveNext方法……");
                Boolean result = iterator.MoveNext();
                Console.WriteLine("MoveNext方法返回的{0}", result);
                if (!result)
                {
                    break;
                }
                Console.WriteLine("获取当前值……");
                Console.WriteLine("获取到的当前值为{0}", iterator.Current);
            }
            Console.ReadKey();
        }
    }
     
    ------------------------------------------------------------------------------------------
    public class List
    {
        //using System.Collections;
        public static IEnumerable Power(int number, int exponent)
        {
            int counter = 0;
            int result = 1;
            while (counter++ < exponent)
            {
                result = result * number;
                yield return result;
            }
        }
     
        static void Main()
        {
            // Display powers of 2 up to the exponent 8:
            foreach (int i in Power(2, 8))
            {
                Console.Write("{0} ", i);
            }
        }
    }
  • 相关阅读:
    JDBC存取二进制文件示例
    java多线程向数据库中加载数据
    Lucene建索引代码
    postgresql存储二进制大数据文件
    java项目使用Echarts 做柱状堆叠图,包含点击事件
    子页面获取父页面控件
    JSTL和select标签的组合使用
    log4j配置祥解
    IT项目经理应具备的十大软技能
    Spring和Struct整合的三个方法
  • 原文地址:https://www.cnblogs.com/One-dream-man/p/3500684.html
Copyright © 2011-2022 走看看