0Pricing
C# Academy · 课时

使用 yield return 的迭代器方法

一次生成一个元素的序列。

使用 yield return 的迭代器方法 是 CoddyKit 上的免费 C# Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

什么是迭代器方法

迭代器方法使用 yield return 一次生成一个值,从而产生值序列。编译器会将它转换为状态机,因此您不必自己构建和管理列表。

您的第一个 yield return

每个 yield return 都会将一个值交给调用者,并暂停方法的执行。下一次迭代时,执行会从该语句之后继续。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> FirstThree()
    {
        yield return 1;
        yield return 2;
        yield return 3;
    }

    public static void Main()
    {
        foreach (var n in FirstThree())
            Console.WriteLine(n);
    }
}

在循环中使用 yield return

大多数迭代器都会在循环内部生成值。这里我们生成前 count 个偶数,而且完全不会分配集合。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Evens(int count)
    {
        for (int i = 0; i < count; i++)
            yield return i * 2;
    }

    public static void Main()
    {
        foreach (var n in Evens(5))
            Console.WriteLine(n);
    }
}

方法返回 IEnumerable

迭代器方法必须返回 IEnumerable<T> 或 IEnumerator<T>,也可以返回相应的非泛型版本。您不能使用带值的 return;只能使用 yield return。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<string> Greetings()
    {
        yield return "hello";
        yield return "hi";
        yield return "hey";
    }

    public static void Main()
    {
        foreach (var g in Greetings())
            Console.WriteLine(g);
    }
}

执行会暂停并恢复

每次生成值之间的状态会自动保留。局部变量会在暂停期间保持其值,这正是生成累计总和如此简单的原因。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> RunningTotal(IEnumerable<int> nums)
    {
        int total = 0;
        foreach (var n in nums)
        {
            total += n;
            yield return total;
        }
    }

    public static void Main()
    {
        foreach (var t in RunningTotal(new[] { 1, 2, 3, 4 }))
            Console.WriteLine(t);
    }
}

生成无限序列

由于值是按需生成的,迭代器可以安全地描述无限序列。调用方决定何时停止获取值。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Naturals()
    {
        int i = 1;
        while (true) yield return i++;
    }

    public static void Main()
    {
        int taken = 0;
        foreach (var n in Naturals())
        {
            Console.WriteLine(n);
            if (++taken == 5) break;
        }
    }
}

转换输入序列

迭代器非常适合构建管道:从一个序列读取元素,对它们进行转换,然后延迟生成结果。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<string> Labelled(IEnumerable<int> nums)
    {
        foreach (var n in nums)
            yield return "item-" + n;
    }

    public static void Main()
    {
        foreach (var s in Labelled(new[] { 10, 20, 30 }))
            Console.WriteLine(s);
    }
}

使用迭代器筛选

要进行筛选,只需生成您需要的元素。被跳过的元素永远不会生成,因此下游代码看不到它们。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> OnlyPositive(IEnumerable<int> nums)
    {
        foreach (var n in nums)
            if (n > 0) yield return n;
    }

    public static void Main()
    {
        foreach (var n in OnlyPositive(new[] { -2, 5, -1, 8 }))
            Console.WriteLine(n);
    }
}

编译器构建状态机

在幕后,编译器会将您的迭代器重写为一个实现 IEnumerator<T> 的类,并跟踪隐藏的状态字段和 Current 值。所有这些机制都由编译器免费为您提供。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<char> Letters()
    {
        yield return 'a';
        yield return 'b';
        yield return 'c';
    }

    public static void Main()
    {
        IEnumerator<char> e = Letters().GetEnumerator();
        while (e.MoveNext())
            Console.WriteLine(e.Current);
    }
}

组合多个迭代器

迭代器可以自然地链接起来,因为每个迭代器都会返回 IEnumerable<T>。将一个迭代器的输出传给下一个,就能构建出易读的管道。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Range(int start, int count)
    {
        for (int i = 0; i < count; i++) yield return start + i;
    }
    static IEnumerable<int> Squares(IEnumerable<int> nums)
    {
        foreach (var n in nums) yield return n * n;
    }

    public static void Main()
    {
        foreach (var n in Squares(Range(1, 4)))
            Console.WriteLine(n);
    }
}

亲自尝试

编写一个迭代器,将输入序列分批处理为固定大小的块。它会按需生成列表,展示如何在一个简洁的迭代器中容纳大量逻辑。

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<List<int>> Batch(IEnumerable<int> source, int size)
    {
        var bucket = new List<int>();
        foreach (var n in source)
        {
            bucket.Add(n);
            if (bucket.Count == size) { yield return bucket; bucket = new List<int>(); }
        }
        if (bucket.Count > 0) yield return bucket;
    }

    public static void Main()
    {
        foreach (var group in Batch(new[] { 1, 2, 3, 4, 5 }, 2))
            Console.WriteLine(string.Join(",", group));
    }
}

快速检查

回想一下迭代器方法的工作方式。

回顾

迭代器方法使用 yield return 按需生成序列。

  • 方法返回 IEnumerable<T> 或 IEnumerator<T>。
  • 每个 yield return 生成一个值并暂停执行,同时保留局部状态。
  • 它们可以安全地描述无限序列。
  • 编译器会为您生成状态机。

常见问题解答

「使用 yield return 的迭代器方法」课时是免费的吗?

是的 — 「使用 yield return 的迭代器方法」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「使用 yield return 的迭代器方法」这节课中我会学到什么?

一次生成一个元素的序列。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「使用 yield return 的迭代器方法」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 yield return 的迭代器方法
  2. yield break 与提前终止
  3. 惰性求值语义
  4. 自定义可枚举类型
← 返回 C# Academy