阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

简单介绍C#中的yield关键字

38次阅读
没有评论

共计 3082 个字符,预计需要花费 8 分钟才能阅读完成。

导读 本文详细讲解了 C# 中的 yield 关键字,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

在 ”C# 中, 什么时候用 yield return” 中,我们了解到:使用 yield return 返回集合,不是一次性加载到内存中,而是客户端每调用一次就返回一个集合元素,是一种 ” 按需供给 ”。本篇来重温 yield return 的用法,探秘 yield 背后的故事并自定义一个能达到 yield return 相同效果的类,最后体验 yield break 的用法。

回顾 yield return 的用法

以下代码创建一个集合并遍历集合。

class Program
 {static Random r = new Random();
     static IEnumerable GetList(int count)
     {List list = new List();
         for (int i = 0; i 

使用 yield return 也能获得同样的结果。修改 GetList 方法为:

static IEnumerable GetList(int count)
{for (int i = 0; i 

通过断点调试发现:客户端每显示一个集合中的元素,都会到 GetList 方法去获取集合元素。

探密 yield

使用 yield return 获取集合,并遍历。

class Program
{public static Random r = new Random();
    static IEnumerable GetList(int count)
    {for (int i = 0; i 

生成项目,并用 Reflector 反编译可执行文件。在.NET 1.0 版本下查看 GetList 方法,发现该方法返回的是一个 GetList 类的实例。原来 yield return 是 ” 语法糖 ”,其本质是生成了一个 GetList 的实例。

简单介绍 C# 中的 yield 关键字

那 GetList 实例是什么呢?点击 Reflector 中 链接查看。

简单介绍 C# 中的 yield 关键字

  • 原来 GetList 类实现了 IEnumerable 和 IEnumerator 的泛型、非泛型接口
  • yield return 返回的集合之所以能被迭代、遍历,是因为 GetList 内部有迭代器
  • yield return 之所以能实现 ” 按需供给 ”,是因为 GetList 内部有一个_state 字段记录这上次的状态
  • 接下来,就模拟 GetList,我们自定义一个 GetRandomNumbersClass 类,使之能达到 yield return 相同的效果。

    using System;
    using System.Collections;
    using System.Collections.Generic;
    namespace ConsoleApplication2
    {
        class Program
        {public static Random r = new Random();
            static IEnumerable GetList(int count)
            {GetRandomNumbersClass ret = new GetRandomNumbersClass();
                ret.count = count;
                return ret;
            }
            static void Main(string[] args)
            {foreach(int item in GetList(5))
                    Console.WriteLine(item);
                Console.ReadKey();}
        }
        class GetRandomNumbersClass : IEnumerable, IEnumerator
        {
            public int count;// 集合元素的数量
            public int i; // 当前指针
            private int current;// 存储当前值
            private int state;// 保存遍历的状态
            #region 实现 IEnumerator 接口
            public int Current
            {get { return current;}
            }
            public bool MoveNext()
            {switch (state)
                {
                    case 0: // 即为初始默认值
                        i = 0;// 把指针调向 0
                        goto case 1;
                        break;
                    case 1:
                        state = 1;// 先设置原状态
                        if (!(i  GetEnumerator()
            {return this;}
            // 被显式调用的属性
            IEnumerator IEnumerable.GetEnumerator()
            {return GetEnumerator();
            }
            #endregion
        }
    }

    关于 GetRandomNumbersClass 类:

  • count 表示集合的长度,可以在客户端赋值。当调用迭代器的 MoveNext 方法,需要把 count 和当前位置比较,以决定是否可以再向前移动。
  • 字段 i 相当于索引,指针每次移动一位,i 需要自增 1
  • current 表示当前存储的值,外部通过 IEnumerator.Current 属性访问
  • 迭代器的 MoveNext 方法是关键:

  • state 字段是整型,表示产生集合过程中的 3 种状态
  • 当 state 为 0 的时候,说明是初始状态,把索引位置调到 0,并跳转到 state 为 1 的部分
  • 当 state 为 1 的时候,首先把状态设置为 1,然后判断索引的位置有没有大于或等于集合的长度,接着产生集合元素,把 state 设置为 2, 并最终返回 true
  • 当 sate 为 2 的时候,也就是迭代器向前移动一位,再次执行 MonveNext 方法的时候,跳转到 state 为 2 的语句块部分,把索引位置自增 1,再跳转到 state 为 1 的语句块中,产生新的集合元素
    如此循环
  • yield break 的用法

    假设在一个无限循环的环境中获取一个 int 类型的集合,在客户端通过某个条件来终止循环。

    class Program
    {static Random rand = new Random();
        static IEnumerable GetList()
        {while (true)
            {yield return rand.Next(100);
            }
        }
        static void Main(string[] args)
        {foreach (int item in GetList())
            {if (item%10 == 0)
                {break;}
                Console.WriteLine(item);
                 
            }
            Console.ReadKey();}
    }

    以上,当集合元素可以被 10 整除的时候,就终止循环。终止循环的时机是在循环遍历的时候。

    如果用 yield break, 就可以在获取集合的时候,当符合某种条件就终止获取集合。

    class Program
    {static Random rand = new Random();
        static IEnumerable GetList()
        {while (true)
            {int temp = rand.Next(100);
                if (temp%10 == 0)
                {yield break;}
                yield return temp;
            }
        }
        static void Main(string[] args)
        {foreach (int item in GetList())
            {Console.WriteLine(item);             
            }
            Console.ReadKey();}
    }
    总结:
  • yield return 能返回一个 ” 按需供给 ” 的集合
  • yield return 是 ” 语法糖 ”,其背后是一个实现了 IEnuerable,IEnumerator 泛型、非泛型接口的类,该类维护着一个状态字段,以保证 yield return 产生的集合能 ” 按需供给 ”
  • yield break 配合 yield return 使用,当产生集合达到某种条件的时候使用 yield break,以终止继续创建集合
  • 以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值

    阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

    腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

    代金券:在阿里云专用满减优惠券

    正文完
    星哥说事-微信公众号
    post-qrcode
     0
    星锅
    版权声明:本站原创文章,由 星锅 于2024-07-25发表,共计3082字。
    转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
    【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
    阿里云-最新活动爆款每日限量供应
    评论(没有评论)
    验证码
    【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中