zoukankan      html  css  js  c++  java
  • C# 基础小知识之yield 关键字

    对于yield关键字我们首先看一下msdn的解释:

    如果你在语句中使用 yield 关键字,则意味着它在其中出现的方法、运算符或 get 访问器是迭代器。 通过使用 yield 定义迭代器,可在实现自定义集合类型的 IEnumerable 和 IEnumerator 模式时无需其他显式类(保留枚举状态的类,有关示例,请参阅 IEnumerator<T>)。

    yield是一个语法糖

    看msdn 的解释总是让人感觉生硬难懂。其实yield关键字很好理解。首先我们对于性质有个了解。yield是一个语法糖。既然yield是在C#中的一个语法糖,那么就说明yield是对一种复杂行为的简化,就是将一段代码简化为一种简单的形式,方便我们程序员使用。

    那么yield到底是对什么行为的简化。我们首先来看一下yield的使用场景。

    还是来看msdn上的例子。

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
             
                foreach (int i in Power(2, 8, ""))
                {
                    Console.Write("{0} ", i);
                }
                Console.ReadKey();
            }
    
    
            public static IEnumerable<int> Power(int number, int exponent, string s)
            {
                int result = 1;
    
                for (int i = 0; i < exponent; i++)
                {
                    result = result * number;
                    yield return result;
                }
                yield return 3;
                yield return 4;
                yield return 5;
            }
    
        }
    }
    复制代码

    这是msdn上yield的一种使用场景。

    我们首先看一下下面的Power方法。该静态方法返回一个IEnumerablel<int>类型的参数。按照我们平常的做法。应该对数据执行一定操作,然后return一个IEnumerablel<int>类型的参数。我们把Power方法改造如下:

    复制代码
     public static IEnumerable<int> Power(int number, int exponent, string s)
            {
                int result = 1;
                //接口不能实例化,我们这儿new一个实现了IEnumerable接口的List
                IEnumerable<int> example = new List<int>();
                for (int i = 0; i < exponent; i++)
                {
                    result = result * number;
                    (example as List<int>).Add(result);
                }
                return example;
            }
    复制代码

    这是我们平常的思路。但是这样做就有个问题。这儿要new一个List,或者任何实现了IEnumerable接口的类型。这样也太麻烦了吧。要知道IEnumerable是一个常用的返回类型。每次使用都要new一个LIst,或者其他实现了该接口的类型。与其使用其他类型,不如我们自己定制一个实现了IEnumerable接口专门用来返回IEnumerable类型的类型。我们自己定制也很麻烦。所以微软帮我们定制好了。这个类是什么,那就是yield关键字这个语法糖。

    此时就确认,的确是使用了实现枚举接口的类来返回我们需要的数据类型。

    每次yield return <expression>;就会像该类的实例中添加 一条数据。当yield break;的时候停止添加。

    至此yield的用法就很清楚了。当我们需要返回IEnumerable类型的时候,直接yield返回数据就可以了。也不用new一个list,或其他类型。所以yield是一个典型的语法糖。

    yield使用中的特殊情况

    我们看到编译器将我们yield的数据添加到了一个集合中。Power方法在编译器中实例化了一个实现枚举接口的类型。但是我们在Power方法中写一些方法,编译器会如何处理

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                //这儿调用了方法。
                var test = Power(2, 8, "");
                Console.WriteLine("Begin to iterate the collection.");
                //Display powers of 2 up to the exponent of 8:
                foreach (int i in Power(2, 8, ""))
                {
                    Console.Write("{0} ", i);
                }
                Console.ReadKey();
            }
            public static IEnumerable<int> Power(int number, int exponent, string s)
            {
                int result = 1;
                if (string.IsNullOrEmpty(s))
                {
                    //throw new Exception("这是一个异常");
                    Console.WriteLine("Begin to invoke GetItems() method");
                }
    
                for (int i = 0; i < exponent; i++)
                {
                    result = result * number;
                    yield return result;
                }
                yield return 3;
                yield return 4;
                yield return 5;
            }
        }
    }
    复制代码

    按照我们的理解当我们 var test = Power(2, 8, "");的时候确实调用了Power方法。此时应该程序打印Console.WriteLine("Begin to invoke GetItems() method");然后继续执行 Console.WriteLine("Begin to iterate the collection.");方法。所以打印顺序应该是

     Begin to invoke GetItems() method

    Begin to iterate the collection.

    但是我们运行的时候却发现

  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/bruce1992/p/14078723.html
Copyright © 2011-2022 走看看