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

前言

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

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

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

        /// <summary>
        /// 传统迭代方式和yield关键字迭代方式对比
        /// </summary>
        public static void IteratorComparisonRun()
        {
            Console.WriteLine("迭代器方法使用yield关键字:");
            foreach (var number in GetNumbersWithYield())
            {
                Console.WriteLine(number);
            }

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

        /// <summary>
        /// 迭代器方法使用yield关键字
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<int> GetNumbersWithYield()
        {
            for (int i = 0; i < 6; i++)
            {
                yield return i;
            }
        }

        /// <summary>
        /// 传统迭代方法返回一个List<int>
        /// </summary>
        /// <returns></returns>
        public static List<int> GetNumbersWithoutYield()
        {
            var numbers = new List<int>();
            for (int i = 0; i < 6; i++)
            {
                numbers.Add(i);
            }
            return numbers;
        }

输出结果:

yield延迟加载按需获取数据

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

        /// <summary>
        /// yield关键字延迟加载按需获取数据
        /// </summary>
        public static void LazyLoadingRun()
        {
            Console.WriteLine("yield延迟加载按需获取数据 开始...");

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

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

        /// <summary>
        /// 使用yield返回偶数的迭代器方法
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<int> 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<int> TakeWhilePositive(IEnumerable<int> 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。

完整示例代码

参考文章

相关推荐
追逐时光者2 天前
C#/.NET/.NET Core技术前沿周刊 | 第 22 期(2025年1.13-1.19)
【.net】·【c#】·【.net core】·【技术前沿周刊】
追逐时光者4 天前
一个基于 Roslyn 和 AvalonEdit 的跨平台 C# 编辑器
【.net】·【c#】·【开源项目】·【.net core】
追逐时光者5 天前
C#数据结构与算法入门实战指南
【c#】·【开源项目】·【面试指南】
追逐时光者5 天前
一款基于 .NET8 + Vue 开源、免费、跨平台的企业级在线考试系统
【.net】·【c#】·【开源项目】·【.net core】
追逐时光者8 天前
C#/.NET/.NET Core技术前沿周刊 | 第 21 期(2025年1.6-1.12)
【.net】·【c#】·【.net core】·【技术前沿周刊】
追逐时光者9 天前
推荐4款基于.NET开源、功能强大的CMS建站系统
【.net】·【c#】·【开源项目】·【.net core】
追逐时光者9 天前
回顾 2024 年 12 个月的C#/.NET/.NET Core优秀项目和框架简报
【.net】·【c#】·【.net core】·【每月简报】
追逐时光者10 天前
.NET 中管理 Web API 文档的两种方式
【.net】·【c#】·【开源项目】·【.net core】·【拾遗补漏】
追逐时光者12 天前
一个适用于 .NET 的开源整洁架构项目模板
【.net】·【c#】·【开源项目】·【.net core】·【拾遗补漏】