IRONSOFTWAREHOME

C# 中的 Yield 简介--它是什么、如何使用以及何时有用

C# 中的 Yield 简介

Tim Corey

43分58秒

当你第一次接触 C# 中的 yield 关键字时,它可能会让你感到困惑。 它究竟是如何运作的? 何时应该使用 yield return 语句而不是传统的 return 语句? 为了全面理解,我们将根据 Tim Corey 出色的 YouTube 教程" C# 中的 Yield 简介 - 它是什么、如何使用以及何时有用"进行详细解释。

在本指南中,我们将通过时间戳引用 Tim 视频中的特定要点,以便于导航,并包含实际示例,以展示 yield 如何改变您处理数据流、大型集合和惰性求值的方式。

C#中的Yield关键字介绍

Tim 首先介绍了 yield 关键字,并强调它对于初次接触它的开发者来说常常令人困惑。他解释说,yield 语句允许方法暂停执行,保持其状态,然后在下次调用时从中断的地方继续执行。 Tim 强调,了解产量对于高效处理数据至关重要,尤其是在处理大型数据集或实施自定义迭代逻辑时。

设置一个简单的示例:类程序和静态 void main 函数

为了消除干扰,Tim 在 Visual Studio 中创建了一个简单的控制台应用程序,名为"YieldDemoApp"。

Yield在C#中的实际功能

蒂姆随后深入探讨了理论。 在 2:04,他描述了 yield 的行为:yield 语句不会一次性处理整个集合,而是会保留一个位置——就像把拇指放在书里一样——以便执行可以暂停并在以后恢复。

这种行为对于延迟执行至关重要,延迟执行中,值仅在需要时生成,而不是预先计算所有内容。 Tim 的描述清晰地奠定了理解收益率如何运作的基础。

编写演示代码

在类 Program 的静态 void Main 方法中,他使用 Console.WriteLine 设置了"应用程序开始"和"应用程序结束"等基本首尾消息,这有助于在稍后使用 foreach 循环时清晰地可视化流程。

这个初始代码示例完全专注于 yield 的实现,不涉及任何 UI 复杂性。

创建 PersonModel 类

为了演示,Tim 创建了一个名为 PersonModel 的类,该类具有 FirstName 和 LastName 属性以及一个构造函数。 创建 PersonModel 对象时,会打印一条消息,指示初始化的是哪个用户。 这有助于直观地了解对象何时被创建,何时被消耗。

这个简单的生成代码步骤为使用自定义迭代器奠定了基础。

使用传统列表返回构建数据访问类

5:06,Tim 转到 DataAccess 类,该类有一个 GetPeople 方法,返回 IEnumerable 对象。<PersonModel> 。 最初,返回值是一个列表,其中包含三个 PersonModel 实例:Tim Corey、Sue Storm 和 Jane Smith。

这种迭代器方法会在迭代开始之前立即将所有对象加载到内存中——这一点蒂姆后来将其与使用 yield 进行了对比。

用列表演示内存使用情况

运行 foreach 循环后,Tim 发现,在读取第一个元素之前,所有三个用户都已经创建好了。 这凸显了处理大型集合或大型数据集时可能出现的问题——内存使用率高。

Tim 解释说,如果我们有一千个用户,即使我们只需要几个用户,我们也会创建一千个对象,导致内存分配效率低下。

将递延执行改为收益回报

10:01,Tim 修改了 GetPeople 函数,使其使用 yield return 而不是创建临时集合(一个 List)。 每个 yield return 语句都会一次直接输出一个 PersonModel。

方法内部的这段关键代码实现了延迟求值,只有当 foreach 循环需要时才会生成下一个元素。

Tim 还澄清说,该方法的返回类型必须是 IEnumerable。<PersonModel>而使用列表则会违背延迟执行的初衷。

调试:编译器如何生成 yield 代码

Tim 使用断点来逐步完成整个过程。 他证明,在第一次调用 MoveNext 之前,序列为空。 只有当 foreach 需要下一个值时,编译器才会触发迭代器块并执行 yield return num 行,该行会初始化并返回 PersonModel。

Tim 强调,编译器会在底层生成特殊的状态机来管理暂停和恢复的执行。

利用收益率的益处和效率

蒂姆解释了为什么产量如此高效:

您可以一次获取一条记录。

您可以限制所需的整数数量。

  • 避免将整个集合加载到内存中。

  • 提高了可扩展性,尤其是在处理大型文件或数据流时。

通过使用 LINQ 的 .Take(2),Tim 演示了即使存在三个 yield return 语句,也只初始化了两个对象——突出了延迟执行的实际应用。

实际示例:利用收益率生成素数

Tim 创建了一个新的静态 IEnumerable。<int> Generators 类中的 GetPrimeNumbers() 方法。 在这个无限循环中,Tim 使用辅助函数 IsPrimeNumber(int number) 来检查素数。 如果该数是质数,他使用 yield return number 将其输出。

这个例子表明,产量对于安全地处理无限序列至关重要。

如果没有 yield,代码会因为无限消耗内存而崩溃。 然而,利用收益率,延迟执行可以确保按需生成数字。

使用 Take() 获取素数

Tim 接着展示了如何安全地获取固定数量的质数:

var primeNumbers = Generators.GetPrimeNumbers().Take(10000);

这段写在 static void Main 中的代码可以高效地获取 10,000 个素数。

由于收益率是逐个产生数字的,因此内存使用率很低。

自定义迭代:使用 GetEnumerator 和 MoveNext

Tim 更进一步,解释了如何手动控制迭代。

他创建了一个变量 iterator = primeNumbers.GetEnumerator(),然后使用 int i 的 for 循环,并调用 iterator.MoveNext() 手动获取元素。

这种手动方法可以实现自定义迭代——仅在需要时请求下一个值,并且表明该方法会从上次暂停的地方恢复执行。

常见错误:对已生成的集合使用 ToList()

36:45 时,Tim 警告:使用 .ToList() 将 yield 序列转换为 List 会导致立即进行完整求值。

如果对无限序列调用 .ToList(),则可能会导致应用程序崩溃。

Tim 强调 yield return 的目的是为了延迟求值,而调用 .ToList() 会强制执行完全内存实例化,从而打破这种模式。

在使用 LINQ 方法时,Tim 建议谨慎引入 .ToList()。

摘要:为什么收益率是一个强大的工具

Tim 最后强调,虽然 yield 关键字会增加一些开销(维护一个状态机),但它能减少内存使用量并实现惰性求值,因此在处理以下情况时,它是一个强大的工具:

  • 大型数据集

  • 大文件

  • 自定义迭代器

  • 无限序列

数据流

  • 延迟处理

他建议在不同的项目中练习收益率,以加深对收益率回报的理解,并避免常见的陷阱。

最后,Tim邀请观众分享他们在生产代码中如何使用yield。

结论

通过观看 Tim Corey 的视频,我们已经了解了 yield 关键字给 C# 带来的巨大好处。 从创建自定义迭代器到高效管理大型集合,yield 返回使函数返回更加智能、更加节省内存。 无论你处理的是变量 number、变量 point、变量 reader、变量 connection 还是大型数据集,掌握 yield 都能极大地提升你的 C# 编码技能。

如果你之前没有探索过使用 yield,现在正是通过简单的示例来练习它,并更好地了解 yield return 在 C# 编译器中是如何工作的绝佳时机。 欢迎访问 Tim 的官方YouTube 频道,观看更多精彩视频。

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Let's Stay in Touch!

Join our newsletter, you’ll get exclusive access on article updates. We value your privacy

Key in blue circle

立即获取免费的 30 天试用版密钥

Your trial license will be sent to your email address

无任何限制。100% 解锁。无需信用卡。

OR
bullet_checked无需信用卡或创建账户无任何限制。100% 解锁。无需信用卡。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried Iron Suite
获取您的无义务咨询
填写下面的表格或通过sales@ironsoftware.com
您的资料将始终保密。
深受全球数百万工程师信赖
Iron Software 的客户徽标
立即获取您的免费30 天试用密钥
无需信用卡或创建账户