当前位置:首页 > 技术分析 > 正文内容

C#使用yield关键字提升迭代性能与效率

ruisui883个月前 (02-03)技术分析17

前言

yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,减少了内存占用,并允许在迭代时执行复杂逻辑。

传统迭代和yield迭代方式对比

咱们来看看传统迭代方式和yield关键字迭代方式对比,是否如传说中的代码实现起来更简洁和高效:

 /// 
/// 传统迭代方式和yield关键字迭代方式对比
///

public static void IteratorComparisonRun()
{
Console.WriteLine("迭代器方法使用yield关键字:");
foreach (var number in GetNumbersWithYield())
{
Console.WriteLine(number);
}

Console.WriteLine("传统迭代方法返回一个List");
var numbers = GetNumbersWithoutYield();
foreach (var number in numbers)
{
Console.WriteLine(number);
}
}

///
/// 迭代器方法使用yield关键字
///

///
public static IEnumerable GetNumbersWithYield()
{
for (int i = 0; i < 6; i++)
{
yield return i;
}
}

///
/// 传统迭代方法返回一个List
///

///
public static List GetNumbersWithoutYield()
{
var numbers = new List();
for (int i = 0; i < 6; i++)
{
numbers.Add(i);
}
return numbers;
}

输出结果:

yield延迟加载按需获取数据

yield关键字可以通过延迟执行的方式,仅在实际需要时生成数据,从而提高了性能和效率。

 /// 
/// yield关键字延迟加载按需获取数据
///

public static void LazyLoadingRun()
{
Console.WriteLine("yield延迟加载按需获取数据 开始...");

foreach (var number in GetEvenNumbers(11))
{
Console.WriteLine($"返回值 === {number} ===");
Thread.Sleep(500);
}

Console.WriteLine("yield延迟加载按需获取数据 结束...");
}

///
/// 使用yield返回偶数的迭代器方法
///

///
public static IEnumerable GetEvenNumbers(int number)
{
for (int i = 1; i < number; i++)
{
Console.WriteLine($"Yielding {i}");
if (i % 2 == 0)
{
yield return i; //只在需要时生成偶数
}
}
}

输出结果:

yield break显式示迭代结束

yield break:显式示迭代结束,如以下示例所示:

 public static void YieldBreakRun()
{
Console.WriteLine(string.Join(" ", TakeWhilePositive(new int[] { 1, 3, 4, 5, -1, 3, 4 })));
//输出:1 3 4 5

Console.WriteLine(string.Join(" ", TakeWhilePositive(new int[] { 9, 8, 7, 6, 5, -5, 88, 100 })));
//输出:9 8 7 6 5
}

public static IEnumerable TakeWhilePositive(IEnumerable numbers)
{
foreach (int n in numbers)
{
if (n > 0)
{
yield return n;
}
else
{
yield break;
}
}
}

什么情况不能使用yield关键字

  • 带有 in、ref 或 out 参数的方法。
  • Lambda 表达式和匿名方法。
  • 在 C# 13 之前,yield 在具有 unsafe 块的任何方法中都无效。从 C# 13 开始,可以在包含 unsafe 块的方法中使用 yield,但不能在 unsafe 块中使用。
  • 不能在catch和finally块中使用yield return和yield break。
  • 不能在具有catch块的try块中使用yield return和yield break。
  • 可以在只有finally块的try块中使用yield return和yield break。

完整示例代码

  • https://github.com/YSGStudyHards/DotNetGuide/tree/main/DotNetGuidePractice

参考文章

  • https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/statements/yield

  • 免费开源的程序员简历模板

  • 了解作者&获取更多学习资料

  • 程序员常用的开发工具软件推荐

  • 加入DotNetGuide技术社区交流群

  • C#/.NET/.NET Core推荐学习书籍

  • C#/.NET/.NET Core学习视频汇总

  • .NET/.NET Core ORM框架资源汇总

  • C#/.NET/.NET Core开发者学习路线集

  • C#/.NET/.NET Core面试宝典(基础版)

  • C#/.NET/.NET Core优秀项目和框架推荐

  • C#/.NET/.NET Core学习、工作、面试指南

学习是一个永无止境的过程,你知道的越多,你不知道的也会越多,在有限的时间内坚持每天多学一点,你一定能成为你想要成为的那个人。不积跬步无以至千里,不积小流无以成江海!

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/1359.html

分享给朋友:

“C#使用yield关键字提升迭代性能与效率” 的相关文章

适合旧电脑2022年值得推荐的 10 款轻量级 Linux 发行版

推荐 10 款轻量级Linux 发行版,它们是 2022 年的轻量级、对旧硬件友好的 Linux 发行版。1、Linux LiteLinux Lite 是一款基于#ubuntu# 和 Debian 的、正在不断开发和完善的 Linux 发行版,极好看的 Xfce 桌面,并基于 Ubuntu,采用了...

vue3中父子组件之间传值的详解

首先我们回顾一下vue2中父子组件是怎么传值的,然后对比vue3进行详解。一、vue2中父子组件传值<!-- 父组件 --> <template> <div> // name:父组件把值传给子组件test-child // childFn:...

USB电池充电基础:应急指南

USB为便携设备供电与其串行通信功能一样,已经成为一种标准应用。如今,USB 供电已经扩展到电池充电、交流适配器及其它供电形式的应用。应用的普及带来的一个显著效果是便携设备的充电和供电可以互换插头和适配器。因此,相对于过去每种装置都采用专用适配器的架构相比,目前的解决方案允许采用多种电源进行充电。毋...

学前端,这30个CSS选择器,你必须熟记

你学会了基本的id,class类选择器和descendant后代选择器,然后就觉得完事了吗?如果这样,你就会错过许多灵活运用CSS的机会。虽然本文提到的许多选择器都属于CSS3,并且只能在现代的浏览器中使用,但学会这些是大有好处的。什么是CSS选择器呢?每一条css样式定义由两部分组成,形式如下:[...

佳能 EOS R8 深度评测

佳能 EOS R8 的定位是入门级全画幅无反光镜可换镜头相机。尽管在产品阵容中处于这一位置,R8 仍然是一个强大的相机,配备了先进的 R6 II 同款成像传感器、快速处理器和令人难以置信的自动对焦系统,体积小、重量轻、价格低。这款相机是发烧友、旅行者、家庭以及任何想要全画幅传感器相机的人的绝佳选择。...

js中数组filter方法的使用和实现

定义filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。语法var newArray = arr.filter(callback(element[, index[, selfArr]])[, thisArg])参数callback循环数组每个元素时调用的回调函数。回调函...