C# yield 关键字

yield 关键字执行对列表、数组等集合的自定义迭代。


yield 关键字的两种形式

yield 关键字有两种形式:

  • yield return - 在每次迭代时返回一个表达式
  • yield break - 终止迭代

Iterator 中的 yield return

yield 关键字在迭代器中使用方式如下:

yield return <expression>; 

我们在迭代器中使用 yield return

using System;
using System.Collections.Generic;
class Program
{
    // define an iterator method
    static IEnumerable<int> getNumber()
    {
        // create a list of integers 
        List<int> myList = new List<int> { -1, -4, 3, 5 };

        foreach (var num in myList)
        {
            // returns positive number from myList 
if (num >= 0) { yield return num; // location of the code is preserved // so on the next iteration getNumber() is executed from here Console.WriteLine("...."); }
} } static void Main() { // display return values of getNumber() foreach (var items in getNumber()) { Console.WriteLine(items); } } }

输出

3
....
5
....

在上面的示例中,我们在 Main() 中的 foreach 循环中调用了 getNumber() 方法。在 getNumber() 方法内部,我们使用了 yield return

在这里,当 Main() 中的 foreach 调用 getNumber() 时,getNumber() 内部的代码会被执行,直到遇到 yield return

当执行到 yield return 时,代码的当前位置会被保留,然后控制权返回给调用者(即 foreach 循环),并打印 **3**。

foreach 的下一次迭代中,getNumber() 方法会再次被调用。这次,getNumber() 将从之前保留的位置继续执行。这意味着:

Console.WriteLine("....");

Console.WriteLine("...."); 会被执行,然后 getNumber() 继续执行,直到遇到下一个 yield return,并且这个过程会一直持续到 myList 的迭代完成。

让我们通过一张图来讨论上述程序的运行机制。


yield return 的工作原理

yield return is returning values to the iterator method
yield return 的工作原理

1. foreach 调用 getNumber() - 首先,Main() 函数内的代码开始执行。在 Main() 中,我们有一个 foreach 循环,它调用 getNumber() 方法。

2. 在 getNumber() 内部,创建了 myList

3. 然后,getNumber() 中的 foreach 循环开始迭代 myList。请注意这段代码:

if (num >= 0)
{
    yield return num;

    // location of the code is preserved 
    // so on the next iteration getNumber() is executed from here 
    Console.WriteLine("....");
}

num = **3** 时,num >= 0 返回 True,并且遇到了 yield return。此时会发生两个操作:

  • 暂停 getNumber() 并保留当前代码位置
  • 将控制权返回给 foreach 循环(调用者)

4. 控制权返回给调用者 - 在这里,返回的值 **3** 被打印出来,然后 foreach 开始下一次迭代。

在下一次迭代中,getNumber() 方法再次被调用。在此次调用中,getNumber() 将从保留的位置恢复执行。

这意味着 Console.WriteLine("...."); 会被执行。

现在,在 if 块中,num = 5,所以 num >= 0True。再次遇到 yield return

5. 控制权再次返回给调用者(foreach 循环内)。在这里,**5** 被打印出来,foreach 在下一次迭代中调用 getNumber()

该方法从保留的位置恢复执行并打印 ....。由于 myList 中没有其他元素了,迭代停止。


常见问题

为什么使用 yield 关键字?

如果不使用 yield return,我们需要创建一个临时集合。例如:

using System;
using System.Collections.Generic;
class Program
{
    // define an iterator method 
    static IEnumerable<int> getEven()
    {
        // create a list of integers 
        List<int> myList = new List<int>() { 1, 2, 3, 4, 5 };

// create an empty temporary list List<int> tempList = new List<int>();
// iterate through myList foreach (var i in myList) { if (i % 2 == 0) { // adds i to temporary list tempList.Add(i); } } return tempList; } static void Main() { // display return values of getEven() foreach (var items in getEven()) { Console.WriteLine(items); } } }

输出

2
4

在这里,我们创建了一个临时列表 tempList,它存储了 myList 中的所有偶数。

创建临时列表会减慢计算速度,并在处理大量值时占用更多内存。


yield break

yield break 用于结束迭代器(列表、数组等)块。让我们看一个例子来更清楚地理解它。

using System;
using System.Collections.Generic;
class Program
{
    // define an iterator method
    static IEnumerable<string> getString()
    {
        // create a list of strings 
        List<string> myList = new List<string> { "Sun", "Mon", "Tue" };

        foreach (var day in myList)
        {
            if (day == "Mon")
            {
// terminates the iterator block after encountering "Mon" yield break;
} yield return day; } } static void Main() { // display return values of getString() foreach (var items in getString()) { Console.WriteLine(items); } } }

输出

Sun

getString() 方法中,请注意:

foreach (var day in myList)
{
if (day == "Mon") { // terminates the iterator block after encountering "Mon" yield break; }
yield return day; }

这里,

  • "Sun"=="Mon"False,因此 if 块未执行。程序执行 yield return day 并将 "Sun" 返回给 getString()
  • "Mon" == "MonTrue,因此 if 块被执行。在这里,遇到了 yield break,它结束了迭代器块,不返回任何内容。

基本上,如果遇到 yield break,则表示集合中已没有更多元素。

注意: yield breakbreak 语句不同,因为 break 语句在常规方法中终止最内层的循环,而 yield break 终止迭代器方法并将程序控制权转移给调用者。

yield break 的作用类似于不返回任何内容的 return 语句。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战