当前位置: 首页 > news >正文

C# --- yield关键字 和 Lazy Execution

C# --- yield关键字 和 Lazy Execution

  • 延迟执行(Lazy Execution)
  • yield关键字
  • lazy execution与yield的关系
  • LINQ 和 lazy exectuion

延迟执行(Lazy Execution)

  • 延迟执行指操作不会立即计算结果,而是在实际需要数据时才执行计算。这种方式避免一次性加载所有数据,节省内存并提升性能。
  • 典型应用:LINQ查询、foreach迭代。
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var query = numbers.Where(n => {
    Console.WriteLine($"过滤 {n}"); // 副作用代码,用于观察执行时机
    return n % 2 == 0;
});

Console.WriteLine("查询已定义,但尚未执行过滤");
foreach (var num in query) // 实际执行过滤操作
{
    Console.WriteLine($"结果: {num}");
}

output:
查询已定义,但尚未执行过滤
过滤 1
过滤 2
结果: 2
过滤 3
过滤 4
结果: 4
过滤 5
  • Where方法返回的是IEnumerable<T>,但此时不会执行过滤逻辑。
  • 实际过滤发生在foreach遍历时,逐个元素处理
  • lazy execution的实现原理用到了yield关键字

yield关键字

  • 简化迭代器实现:通过yield return按需生成值,自动生成IEnumerable或IEnumerator。
  • 启用延迟执行:迭代器方法在遍历时逐步执行,而非一次性运行完毕。
  • yield return:生成一个值,并暂停方法执行,直到下次迭代。
  • yield break:终止迭代。

示例:生成斐波那契数列

using System;
using System.Collections.Generic;

public class Program
{
    public static IEnumerable<int> GenerateFibonacci(int count)
    {
        int a = 0, b = 1;
        for (int i = 0; i < count; i++)
        {
            Console.WriteLine($"生成第 {i+1} 项");
            yield return a; // 暂停并返回值
            int temp = a;
            a = b;
            b = temp + b;
        }
    }

    public static void Main()
    {
        var fibSequence = GenerateFibonacci(5); // 此时不会执行方法体, 只返回迭代器
        Console.WriteLine("开始遍历");
        foreach (var num in fibSequence) 
        {
        	// 每次循环触发一次迭代,执行方法体里的代码
            Console.WriteLine($"结果: {num}");
        }
    }
}

output:
开始遍历
生成第 1 项
结果: 0
生成第 2 项
结果: 1
生成第 3 项
结果: 1
生成第 4 项
结果: 2
生成第 5 项
结果: 3
  • 调用GenerateFibonacci(5)时,方法体不会立即执行。
  • 每次foreach循环触发一次迭代,执行到下一个yield return后暂停

lazy execution与yield的关系

核心机制

  • yield关键字生成的迭代器方法会自动实现延迟执行。
  • 迭代器方法被调用时,返回一个IEnumerable对象,但方法体代码不会立即运行
  • 代码的实际执行由foreach或MoveNext()触发,按需生成值

立即执行(Eager Evaluation)

public List<int> GetNumbersEager()
{
    List<int> numbers = new List<int>();
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine($"立即生成: {i}");
        numbers.Add(i);
    }
    return numbers; // 所有数据已生成
}

// 调用时立即生成所有元素:
var list = GetNumbersEager(); // 输出所有"立即生成: x"
foreach (var num in list) { /* 直接遍历已生成的列表 */ }

延迟执行(使用yield)

public IEnumerable<int> GetNumbersLazy()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine($"延迟生成: {i}");
        yield return i; // 按需生成
    }
}

// 调用时仅定义迭代器:
var sequence = GetNumbersLazy(); // 无输出
foreach (var num in sequence) 
{
    // 每次循环触发一次生成
}

延迟生成: 0
延迟生成: 1
延迟生成: 2
...

何时选择延迟执行?

  • 处理大数据集:避免一次性加载所有数据到内存。
  • 生成无限序列:如斐波那契数列、实时数据流。
  • 复杂计算:按需计算,减少不必要的开销。

经典案例

// 生成无限随机数序列
public static IEnumerable<int> InfiniteRandomNumbers()
{
    Random rand = new Random();
    while (true)
    {
        yield return rand.Next();
    }
}

// 仅取前3个随机数
foreach (var num in InfiniteRandomNumbers().Take(3))
{
    Console.WriteLine(num);
}

LINQ 和 lazy exectuion

  • 在 C# 中,延迟执行(Lazy Execution) 是 LINQ(Language Integrated Query)的核心特性之一。它允许 LINQ 查询在定义时不立即执行,而是推迟到实际需要数据时才进行计算。这种机制显著优化了性能,尤其是在处理大数据集或链式操作时。
  • 延迟执行:LINQ 查询(如 Where、Select、OrderBy)默认返回 IEnumerable 或 IQueryable,这些查询不会立即执行,而是在以下时机触发计算:
  • 遍历结果(如 foreach 循环)。
  • 调用强制立即执行的方法(如 ToList()、ToArray()、Count())。
  • 底层实现:LINQ 方法通过 yield return 和迭代器模式实现延迟执行,按需生成数据
var numbers = new List<int> { 1, 2, 3, 4, 5 };

// 定义查询(未执行)
var query = numbers
    .Where(n => {
        Console.WriteLine($"过滤 {n}");
        return n % 2 == 0;
    })
    .Select(n => {
        Console.WriteLine($"映射 {n}");
        return n * 10;
    });

Console.WriteLine("查询已定义,尚未执行");
numbers.Add(6); // 修改原集合

// 触发执行
foreach (var num in query)
{
    Console.WriteLine($"结果: {num}");
}

查询已定义,尚未执行
过滤 1
过滤 2
映射 2
结果: 20
过滤 3
过滤 4
映射 4
结果: 40
过滤 5
过滤 6
映射 6
结果: 60

相关文章:

  • 英语学习4.11
  • C#MQTT协议服务器与客户端通讯实现(客户端包含断开重连模块)
  • Day 8 上篇:深入理解 Linux 驱动模型中的平台驱动与总线驱动
  • JS实现文件点击或者拖拽上传
  • Sql with as 语句
  • 重读《人件》Peopleware -(6)Ⅰ管理人力资源Ⅴ-帕金森定律重探 Parkinson’s Law Revisited
  • [算法题:快排(一)]颜色分类
  • 【unity游戏开发介绍之UGUI篇】UGUI概述和基础使用
  • ThingsBoard3.9.1 MQTT Topic(1)
  • Apollo源码总结
  • 寻找峰值 --- 二分查找
  • 主流开源大模型评估数据集
  • 【工具】Fiddler抓包
  • 本地部署大模型(ollama模式)
  • 【Code】《代码整洁之道》笔记-Chapter13-并发编程
  • 机械臂只有位置信息是否可以进行手眼标定?
  • HDF5文件格式:数据类型与读写功能详解
  • asm汇编源代码之CPU型号检测
  • Axure中继器(Repeater): 列表多选和 列表查询
  • Python 数据分析01 环境搭建教程
  • 商丘柘城做网站/百度云网盘登录入口
  • 免费php空间/龙岗seo优化
  • 城乡与住房建设厅网站/网络推广方式方法
  • 项目建设成效怎么写/seo优化分析
  • 胶州城乡建设局网站/b2b平台是什么意思
  • 做网站需要看什么书/国内最新新闻摘抄