c# yield关键字的用法

1.yield实现的功能
yield return:
先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也是用来实现迭代器的功能的。

using static System.Console;
using System.Collections.Generic; class Program
{
//一个返回类型为IEnumerable<int>,其中包含三个yield return
public static IEnumerable<int> enumerableFuc()
{
yield return 1;
yield return 2;
yield return 3;
} static void Main(string[] args)
{
//通过foreach循环迭代此函数
foreach(int item in enumerableFuc())
{
WriteLine(item);
}
ReadKey();
}
} 输出结果:
1
2
3

yield break:
再看下面的代码,只输出了1,2,没有输出3,说明这个迭代器被yield break停掉了,所以yield break是用来终止迭代的。

using static System.Console;
using System.Collections.Generic;
class Program
{
//一个返回类型为IEnumerable<int>,其中包含三个yield return
public static IEnumerable<int> enumerableFuc()
{
yield return 1;
yield return 2;
yield break;
yield return 3;
} static void Main(string[] args)
{
//通过foreach循环迭代此函数
foreach(int item in enumerableFuc())
{
WriteLine(item);
}
ReadKey();
}
} 输出结果:
1
2

2.只能使用在返回类型必须为 IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>的方法、运算符、get访问器中。

3.yield关键字的实现原理
我们用while循环代替foreach循环,发现我们虽然没有实现GetEnumerator(),也没有实现对应的IEnumerator的MoveNext(),和Current属性,但是我们仍然能正常使用这些函数。

class Program
{
//一个返回类型为IEnumerable<int>,其中包含三个yield return
public static IEnumerable<int> enumerableFuc()
{
yield return 1;
yield return 2;
yield return 3;
} static void Main(string[] args)
{
//用while循环代替foreach
IEnumerator<int> enumerator = enumerableFuc().GetEnumerator();
while (enumerator.MoveNext())
{
int current = enumerator.Current;
WriteLine(current);
}
ReadKey();
}
} 输出结果:
1
2
3

至于为什么会出现这种情况,我们可以用ILSpy对生成的exe进行反编译来找到原因。
由于直接反编译成C#会变为原样

所以我们选择反编译为带C#注释的IL代码,虽然可读性差点,但是可以详细的了解其中过的原理。
先来看Program翻译的情况,编译的时候自动生成了一个新的类。

接下来我们来仔细看这些代码,EnumerableFuc()返回了这个新的类。

看这个代码自动生成的类的实现,发现它继承了IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>,这时我们应该已经能猜到这个新的类就是我们没有实现对应的IEnumerator的MoveNext(),和Current属性,但是我们仍然能正常使用这些函数的原因了。

我们再来看一下这个类具体是如何实现迭代的呢,我们主要来看一下MoveNext()函数


每次调用MoveNext()函数都会将state加1,一共进行了4次迭代,前三次返回true,最后一次返回false,代表迭代结束。这四次迭代对应被3个yield return语句分成4部分的enumberableFuc()中的语句。

用enumberableFuc()来进行迭代的真实流程就是:
1.运行enumberableFuc()函数,获取代码自动生成的类的实例。
2.接着调用GetEnumberator()函数,将获取的类自己作为迭代器开始迭代。
3.每次运行MoveNext(),state增加1,通过switch语句可以让每次调用MoveNext()的时候执行不同部分的代码。
4。MoveNext()返回false,结束。
这也能说明yield关键字其实是一种语法糖,最终还是通过实现IEnumberable<T>、IEnumberable、IEnumberator<T>和IEnumberator接口实现的迭代功能。

 

c# yield关键字的用法的更多相关文章

  1. yield关键字的用法

    在上一篇文章中,说了下foreach的用法,但是还是比较复杂的,要实现接口才能进行遍历,有没有简单些的方法呢?答案是肯定的.且看下面. yield关键字的用法: 1.为当前类型添加一个任意方法,但是要 ...

  2. c# 递归 yield关键字的用法

    1.yield实现的功能 yield return: 先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也是用来实现迭代器的功能的. u ...

  3. .NET中的yield关键字

    浅谈yield http://www.cnblogs.com/qlb5626267/archive/2009/05/08/1452517.html .NET中yield关键字的用法 http://bl ...

  4. c# yield关键字原理详解

    c# yield关键字的用法 1.yield实现的功能 yield return: 先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也 ...

  5. C# 中yield关键字解析

    前言 前段时间了解到yield关键字,一直觉得还不错.今天给大家分享一下yield关键字的用法.yield return 返回集合不是一次性返回所有集合元素,而是一次调用返回一个元素.具体如何使用yi ...

  6. yield关键字用法与解析(C# 参考)

    yield 关键字向编译器指示它所在的方法是迭代器块. 编译器生成一个类来实现迭代器块中表示的行为. 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值. 这是一个返 ...

  7. yield关键字详解与三种用法

    本篇文章比较硬核, 适合有一定Python基础的读者阅读, 如果您对Python还不甚了解可以先关注我哦, 我会持续更新Python技术文章 yield详解 yield与return相同每次调用都会返 ...

  8. 从yield关键字看IEnumerable和Collection的区别

    C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的.相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制.但是即使你知道这个机制,你也很容易 ...

  9. C#的yield关键字

    using System; using System.Collections.Generic; using System.Reflection; using System.Text.RegularEx ...

  10. C# 基础小知识之yield 关键字 语法糖

    原文地址:http://www.cnblogs.com/santian/p/4389675.html 对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味 ...

随机推荐

  1. 基于nodejs的本地文件增删改查的工具代码

    一.代码封装 这是一个使用node.js实现的对本地文件进行增删改查的工具代码封装,其中代码结尾包含了使用方法示例,具体封装代码如下: // jsonTool.js const fs = requir ...

  2. HarmonyOS运动开发:打造便捷的静态快捷菜单

    鸿蒙核心技术##运动开发# 前言 在运动类应用中,用户往往需要快速访问常用功能,如查看成绩.赛事信息或开始运动.为了提升用户体验,鸿蒙(HarmonyOS)提供了静态快捷菜单功能,允许用户从桌面直接跳 ...

  3. 你应该懂的AI大模型(六)之 transformers

    一.Transformer与transformers 结论:Transformer是模型架构,transfortmers是库. 问:为什么我们要知道Transformer与transformers呢? ...

  4. CAE技术的局限性讨论-CAE咨询

    计算机辅助工程(Computer-Aided Engineering, CAE)技术是现代工程领域中不可或缺的一部分,它通过数值模拟和计算分析,为工程设计和优化提供了强大的工具.然而,就像任何技术一样 ...

  5. Python 潮流周刊#108:AI 会取代初级开发者吗?(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 400+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  6. Blazor学习之旅(4)数据共享

    本篇,我们来了解下在Blazor中数据是如何共享的,组件之间又该如何传递参数. 关于Blazor组件 在 Blazor 中,从名为"组件"的自包含代码部分生成 UI.每个组件都可以 ...

  7. CSP-S 2024 游记

    上午 上午打板+睡觉.希望能比去年有进步. 下午 下午进考场,好像来早了,一直没见到带考的老师,于是自己先进去了. 鼠标不好用,滚轮坏了,申请换一个.结果更不好用,过一会就卡一下.于是换了个位置,鼠标 ...

  8. 【EF Core】框架是如何识别实体的属性和主键v

    在上一篇水文中,老周生动形象地解释了 DbContext 是如何识别实体 Set 的,大伙伴们可能会产生新的疑惑:实体是识别了,但,实体的属性或字段列表,它是怎么识别并映射给数据表的列的呢? 用过 E ...

  9. 前端开发系列085-Node篇之global

    本文介绍Node中的全局对象,包括global本身以及控制台输出对象Console.require函数.定时器相关方法以及\_\_filename和\_\_dirname等全局变量. 一.global ...

  10. iga 入门之 总体合成

    简介 摘自 流体力学数值方法 概括地说,总体合成就是将所有单元的\(A_{ij}^{(e)}.f_i^{(e)}\)进行累加,最终形成\(A_{nm}.f_n\),从而产生总体有限元方程 \[A_{n ...