news 2026/7/19 6:33:48

C# yeild的使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C# yeild的使用

yield是 C# 中一个非常巧妙的语法糖,它的核心作用是实现“延迟执行(Lazy Evaluation)”

简单来说,它允许你在一个方法中逐个返回数据,而不需要一次性把所有数据都计算好并塞进一个List里返回。

🎬 核心概念:从“批发”到“零售”

为了理解yield,我们先看一个不使用yield的传统写法:

// 传统写法:一次性生成所有数据(批发)publicList<int>GetNumbers(intcount){varlist=newList<int>();for(inti=0;i<count;i++){list.Add(i);// 把所有数字都塞进内存里的集合}returnlist;// 最后一次性返回整个集合}

缺点:如果count是 100 万,这个方法会瞬间在内存中分配一个包含 100 万个元素的数组,造成极大的内存浪费。

现在看看使用yield的写法:

// yield 写法:按需生成数据(零售)publicIEnumerable<int>GetNumbersYield(intcount){for(inti=0;i<count;i++){yieldreturni;// 每次吐出一个数字,然后“暂停”在这里}}

优点:调用这个方法时,它根本不会立刻执行循环。只有当外部真正去读取下一个数据时,它才会执行一次循环,吐出一个值,然后暂停。内存中永远只存在当前这一个数字。

🛠️ 两个核心关键字

  1. yield return:返回当前值,并记住当前的执行状态(包括局部变量、循环索引等)。下次调用时,直接从这行代码的下一行继续执行。
  2. yield break:提前结束迭代,相当于普通方法里的return

💡 典型应用场景

1. 读取超大文件或数据流

假设你要读取一个 10GB 的日志文件,如果用File.ReadAllLines(),内存直接撑爆。用yield可以逐行处理:

publicIEnumerable<string>ReadLargeFile(stringfilePath){using(varreader=newStreamReader(filePath)){stringline;while((line=reader.ReadLine())!=null){yieldreturnline;// 读一行,吐出一行,内存占用极小}}}// 使用时:foreach(varlineinReadLargeFile("huge_log.txt")){if(line.Contains("ERROR"))Console.WriteLine(line);}
2. 实现自定义迭代器

如果你想让你自己写的类支持foreach循环,就可以用yield

publicclassCountdown{privateint_start;publicCountdown(intstart){_start=start;}publicIEnumerator<int>GetEnumerator(){for(inti=_start;i>=0;i--){yieldreturni;}}}// 使用时:varcountdown=newCountdown(5);foreach(varnumincountdown){Console.WriteLine(num);// 输出 5, 4, 3, 2, 1, 0}
3. 提前终止(yield break)
publicIEnumerable<int>GetEvenNumbers(intmax){for(inti=0;i<=max;i++){if(i>10)yieldbreak;// 如果超过10,直接结束整个迭代if(i%2==0)yieldreturni;}}

⚠️ 必须注意的“坑”

  1. 只能返回特定类型:包含yield的方法,返回类型只能是IEnumerableIEnumerable<T>IEnumeratorIEnumerator<T>。不能直接返回List<T>或数组。
  2. 延迟执行的副作用
    varquery=GetNumbersYield(100);// 此时循环一次都没执行!// 只有走到这里,循环才开始foreach(variteminquery){...}
    如果你在GetNumbersYield里面有参数校验(比如if(count < 0) throw...),在调用方法时不会报错,只有在foreach第一次迭代时才会报错。
  3. 不要在yield方法里使用try-catch-finally包裹yield return:C# 编译器不允许在包含yield returntry块中使用catch(但可以使用finally)。

📌 总结

yield的本质是状态机。C# 编译器在底层帮你把yield方法编译成了一个复杂的类,自动帮你保存了局部变量和执行位置。

一句话口诀:当数据量很大,或者数据是按需生成的,且你只需要用foreach去遍历它时,果断使用yield return


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/19 6:33:38

基于视频动态目标无感定位技术智慧城市全栈解决方案

基于视频动态目标无感定位技术智慧城市全栈解决方案前置说明本文由一线空间感知资深技术专家执笔&#xff0c;全文剔除修饰虚词、冗余连接语句&#xff0c;高密度锚定视频孪生、数字孪生、无感定位、跨镜头跟踪、跨视域融合、实景流解析、无前置建模、物理空间透明化管理、空间…

作者头像 李华
网站建设 2026/7/19 6:31:58

C++双向链表调试实战:用GDB和Valgrind解决内存泄漏与指针错误

1. 项目概述&#xff1a;为什么调试链表是C程序员的必修课双向链表&#xff0c;这个数据结构课上的常客&#xff0c;在实际的C项目开发中&#xff0c;尤其是涉及底层内存管理、高频数据增删的场景里&#xff0c;扮演着极其重要的角色。它不像std::list那样封装得严严实实&#…

作者头像 李华
网站建设 2026/7/19 6:30:47

Yii框架登录功能实现与安全实践

1. Yii框架登录功能全应用解析Yii作为一款高效、安全的PHP框架&#xff0c;其内置的认证系统为开发者提供了完整的登录解决方案。在实际项目中&#xff0c;我们经常需要实现一套登录系统&#xff0c;能够覆盖前台用户登录、后台管理员登录、API接口认证等多种场景。本文将基于Y…

作者头像 李华
网站建设 2026/7/19 6:28:55

Inkling生产级语言模型:本地部署、数据隐私与工程实践指南

如果你正在寻找一个既能在本地安全部署&#xff0c;又具备生产级稳定性的语言模型&#xff0c;那么 Thinking Machines 最新发布的 Inkling 值得你重点关注。与那些需要云端 API 调用或者配置复杂的大模型不同&#xff0c;Inkling 瞄准的是企业级开发者的真实需求&#xff1a;数…

作者头像 李华
网站建设 2026/7/19 6:27:59

保姆级】从零学会LangChain调用大模型!统一接口+代码实战

为提升开发效率&#xff0c;新版 LangChain1.2.x将不同厂商 AI 大模型的调用逻辑做了统一封装&#xff0c;整合到init_chat_model中完成统一调用&#xff0c;大幅简化多模型适配开发。核心参数仅需关注两个&#xff1a; model&#xff1a;指定具体的模型名称&#xff0c;如 gpt…

作者头像 李华
网站建设 2026/7/19 6:27:39

Unity手游微信登录与分享功能集成实战:从环境配置到真机调试

1. 项目概述与核心价值 最近在做一个Unity手游项目&#xff0c;需要接入微信登录和分享功能。说实话&#xff0c;第一次在Unity里搞微信SDK集成&#xff0c;踩的坑比预想的要多得多。网上资料虽然不少&#xff0c;但要么是官方文档语焉不详&#xff0c;要么是零散的代码片段&am…

作者头像 李华