C# 过滤数据的三种姿势:yield return、LINQ Where、ToList 全景性能对决

C#基础之 --- 数据过滤 1 应用场景 经常我们会从数据库中查询出DataTable,这个时候显示到页面上的时候就需要过滤掉一些当前用户不能/不希望看到的记录。 此时就要用到数据过滤了。 2 代码 下面是一个过滤掉DataTable中存储的所有人员记录的女性的完整示例: using System; using System.Collections.Generic; using System.Linq; u 阅读详情

测试代码

[MemoryDiagnoser]
public class YieldBenchmark
{
    private readonly Consumer _consumer = new Consumer();

    [Params(100, 10000, 100000)]
    public int N;

    private int[] _intArray;
    private MyClass[] _classArray;
    private MyStruct[] _structArray;

    [GlobalSetup]
    public void Setup()
    {
        _intArray = Enumerable.Range(0, N).ToArray();
        _classArray = Enumerable.Range(0, N).Select(i => new MyClass { Value = i }).ToArray();
        _structArray = Enumerable.Range(0, N).Select(i => new MyStruct { Value = i }).ToArray();
    }


    // ==================== int ====================
    [Benchmark] public void Int_Yield() => YieldInt(_intArray).Consume(_consumer);
    [Benchmark] public void Int_IfYield() => IfYieldInt(_intArray).Consume(_consumer);
    [Benchmark] public List<int> Int_ToList() => YieldInt(_intArray).ToList();
    [Benchmark] public int[] Int_ToArray() => YieldInt(_intArray).ToArray();

    private static IEnumerable<int> YieldInt(int[] source)
    {
        return source.Where(x => x % 2 == 0);
    }

    private static IEnumerable<int> IfYieldInt(int[] source)
    {
        foreach (var item in source)
            if (item % 2 == 0)
                yield return item;
    }

    // ==================== class ====================
    [Benchmark] public void Class_Yield() => YieldClass(_classArray).Consume(_consumer);
    [Benchmark] public void Class_IfYield() => IfYieldClass(_classArray).Consume(_consumer);
    [Benchmark] public List<MyClass> Class_ToList() => YieldClass(_classArray).ToList();
    [Benchmark] public MyClass[] Class_ToArray() => YieldClass(_classArray).ToArray();

    private static IEnumerable<MyClass> YieldClass(MyClass[] source)
    {
        return source.Where(x => x.Value % 2 == 0);
    }

    private static IEnumerable<MyClass> IfYieldClass(MyClass[] source)
    {
        foreach (var item in source)
            if (item.Value % 2 == 0)
                yield return item;
    }

    // ==================== struct ====================
    [Benchmark] public void Struct_Yield() => YieldStruct(_structArray).Consume(_consumer);
    [Benchmark] public void Struct_IfYield() => IfYieldStruct(_structArray).Consume(_consumer);
    [Benchmark] public List<MyStruct> Struct_ToList() => YieldStruct(_structArray).ToList();
    [Benchmark] public MyStruct[] Struct_ToArray() => YieldStruct(_structArray).ToArray();

    private static IEnumerable<MyStruct> YieldStruct(MyStruct[] source)
    {
        return source.Where(x => x.Value % 2 == 0);
    }

    private static IEnumerable<MyStruct> IfYieldStruct(MyStruct[] source)
    {
        foreach (var item in source)
            if (item.Value % 2 == 0)
                yield return item;
    }
}

public class MyClass
{
    public int Value;
}

public struct MyStruct
{
    public int Value;
}

测试结果

MethodNMeanErrorStdDevMedianGen0Gen1Gen2Allocated
Int_Yield100173.4 ns2.64 ns2.47 ns173.3 ns0.0076--48 B
Int_IfYield100156.7 ns0.57 ns0.50 ns156.6 ns0.0088--56 B
Int_ToList100258.2 ns4.85 ns4.77 ns257.4 ns0.1106--696 B
Int_ToArray100277.2 ns5.26 ns5.16 ns278.3 ns0.1144--720 B
Class_Yield100423.1 ns8.19 ns8.41 ns420.5 ns0.0076--48 B
Class_IfYield100394.8 ns4.34 ns4.06 ns394.9 ns0.0100--64 B
Class_ToList100410.5 ns5.47 ns5.11 ns408.9 ns0.18980.0005-1192 B
Class_ToArray100492.8 ns2.29 ns1.79 ns492.7 ns0.1898--1192 B
Struct_Yield100218.6 ns3.82 ns4.09 ns218.3 ns0.0076--48 B
Struct_IfYield100190.5 ns1.33 ns1.04 ns190.9 ns0.0088--56 B
Struct_ToList100263.2 ns6.99 ns20.60 ns274.4 ns0.1109--696 B
Struct_ToArray100306.3 ns4.50 ns3.99 ns307.1 ns0.1144--720 B
Int_Yield1000016,310.8 ns244.84 ns229.02 ns16,303.4 ns---48 B
Int_IfYield1000014,991.2 ns278.83 ns273.85 ns15,040.4 ns---56 B
Int_ToList1000021,684.4 ns419.96 ns483.63 ns21,635.4 ns10.46751.1597-65888 B
Int_ToArray1000023,093.1 ns225.83 ns211.24 ns23,045.3 ns8.48390.5798-53440 B
Class_Yield1000039,518.1 ns786.32 ns772.27 ns39,381.6 ns---48 B
Class_IfYield1000038,522.0 ns246.33 ns230.41 ns38,476.6 ns---64 B
Class_ToList1000032,900.5 ns645.10 ns904.35 ns32,591.2 ns20.81303.4180-131408 B
Class_ToArray1000033,693.9 ns278.96 ns260.94 ns33,711.5 ns16.84571.5259-106224 B
Struct_Yield1000019,381.9 ns319.79 ns299.13 ns19,403.8 ns---48 B
Struct_IfYield1000014,652.0 ns16.89 ns14.10 ns14,653.5 ns---56 B
Struct_ToList1000019,771.0 ns188.52 ns167.12 ns19,717.3 ns10.46751.1597-65888 B
Struct_ToArray1000016,348.6 ns139.48 ns123.65 ns16,322.8 ns8.48390.5798-53440 B
Int_Yield100000145,367.8 ns161.72 ns151.27 ns145,342.5 ns---48 B
Int_IfYield100000134,651.7 ns1,063.77 ns995.06 ns134,108.5 ns---56 B
Int_ToList100000182,513.1 ns571.52 ns534.60 ns182,429.3 ns98.632878.369177.3926525216 B
Int_ToArray100000191,113.4 ns857.08 ns801.71 ns191,026.0 ns88.378970.800867.3828463287 B
Class_Yield100000393,067.4 ns1,592.34 ns1,411.57 ns392,486.7 ns---48 B
Class_IfYield100000386,997.1 ns1,470.07 ns1,375.11 ns386,845.2 ns---64 B
Class_ToList100000595,860.0 ns5,105.46 ns4,775.65 ns596,887.2 ns183.5938163.0859162.10941050004 B
Class_ToArray100000457,150.3 ns4,990.60 ns4,668.21 ns456,151.7 ns181.6406165.5273160.1563925998 B
Struct_Yield100000186,671.9 ns1,434.43 ns1,197.81 ns186,435.3 ns---48 B
Struct_IfYield100000172,955.8 ns2,730.39 ns2,554.01 ns172,108.0 ns---56 B
Struct_ToList100000241,428.5 ns2,556.80 ns2,391.63 ns240,950.8 ns97.900477.880976.9043525206 B
Struct_ToArray100000201,362.2 ns657.62 ns549.15 ns201,645.8 ns84.716867.138763.7207463252 B

总结

  1. list通常比array更占内存
  2. 使用LINQ Where,会生成迭代器对象迭代器对象(WhereArrayIterator),产生48B内存
  3. 手写循环yield return返回,会生成一个状态机,产生56B/64B(引用类型占8B)内存,但平均比LINQ Where稍微快一点
  4. 大数据量用IEnumerable可以减少内存分配
C# 数据库查询语句-第4节.过滤数据(1) C# 数据库查询语句-第4节.过滤数据(1) 作者:陈钰桃 撰写时间:2022 4月17日 第4节. 过滤数据(1) Select Distinct子句 SELECT DISTINCT 子句检索指定列列表中的唯一不同值,换句话说,它从结果集中删除列中的重复值。DISTINCT 子句将所有 NULL 值视为相同的值 语法如下所示: SELECT DISTINCT column_name1, column_name2 , … FROM table_name; A.DISTINCT一个字段的示例 以下语句返回 阅读详情

相关推荐

C# 2.0模拟LINQ:Fluent接口实现原理与工程实践

LINQ是.NET中函数式集合操作的标志性抽象,其核心在于链式调用、延迟执行与类型安全的数据流表达。理解LINQ本质,需回溯至语言能力受限场景——当C# 2.0缺乏Lambda、扩展方法和隐式类型时,开发者如何通过Fluent Interface模式,在不依赖编译器新特性前提下,复现Select/Where/ToList等语义?这涉及Func委托泛型封装、yield return状态机机制、对象生命周期承载数据流等关键技术点。该方案不仅适用于遗留.NET Framework 2.0/3.5系统维护,也为现代

diedangxiang4092的博客 360

C# 数据库查询语句-第4节.过滤数据(2)

C# 数据库查询语句-第4节.过滤数据(2) 作者:陈钰桃 撰写时间:2022 4月27日 第4节.过滤数据(2) 6.Between查找具有两个值之间的值的行 BETWEEN 运算符是一个逻辑运算符,用于指定要测试值的范围。 以下是 BETWEEN 运算符的语法: column | expression BETWEEN start_expression AND end_expression 可以使用大于或等于( >= )且小于或等于( <= )来替换 BETWEEN 运算符,如下所示 col

sult812的博客 833

深入理解IEnumerable<T>:foreach背后的迭代协议与性能本质

IEnumerable<T> 是 .NET 中实现集合遍历的核心接口协议,它定义了‘可被逐一访问’这一行为契约,而非数据容器本身。其原理基于 GetEnumerator()、MoveNext() 和 Current 三要素构成的迭代器模式,并天然支持延迟执行(Deferred Execution)——即仅在 foreach 或 ToList() 等消费时才触发实际计算。这一机制赋予了 LINQ 链式调用高效的数据流水线能力,但也带来重复执行、内存泄漏和 IO 风险等技术挑战。在电商订单导出、日志流解析、实时

weixin_40192258的博客 404

用C#连接数据库并过滤数据

用C#连接数据库并过滤数据 //连接数据库并进行查询数据 string str = "data source=192.168.26.68;initial catalog=Lota;user ID=ss;pwd=k3cloud123;"; using(var conn = new SqlConnection(str))//在using范围内可以使用c...

kuguhuan的博客 579

C#函数式编程三剑客:Select、Where、Aggregate详解

函数式编程中的map、filter和reduce是数据处理的核心操作,在C#中分别对应LINQ的Select、Where和Aggregate方法。这些操作基于延迟执行原理,能够构建高效的数据处理管道,显著提升代码的可读性和维护性。在数据处理、集合转换和聚合计算等场景中,它们能够替代传统的循环操作,实现更声明式的编程风格。C#从3.0版本引入的LINQ技术,使得函数式编程范式与面向对象特性完美融合,特别适用于数据密集型应用开发。掌握Select(映射转换)、Where(条件过滤)和Aggregate(累积计算

weixin_33742618的博客 268

LINQ核心技术解析与性能优化实战

LINQ(Language Integrated Query)是C#中的革命性数据查询技术,通过统一的语法实现多数据源操作。其核心原理是将命令式查询转换为声明式表达式树,在编译时进行类型检查并支持智能提示。技术价值体现在提升开发效率、减少代码量以及优化查询性能上,特别适用于数据库访问、集合处理和XML操作等场景。延迟执行和表达式树机制使LINQ能智能优化查询计划,而GroupBy、Join等操作符为复杂数据分析提供强大支持。在实际工程中,合理使用Include预加载、分页查询和参数化查询等技巧,能有效解决N

weixin_33754065的博客 447

LINQ在C#开发中的高级应用与性能优化

LINQ(Language Integrated Query)是.NET框架中的革命性查询技术,它通过统一的语法模型实现了对多种数据源(内存集合、数据库、XML等)的操作。其核心技术原理包括延迟执行和表达式树,前者通过构建查询计划而非立即执行来优化性能,后者则支持运行时动态生成查询条件。在实际工程应用中,LINQ不仅能显著提升代码可读性,还能通过PLINQ实现并行计算加速,或在Entity Framework中生成高效SQL查询。对于C#开发者而言,深入掌握LINQ的延迟执行特性和表达式树机制,能够解决大数

weixin_33670713的博客 430

Unity开发必备:LINQ to GameObject高效场景对象查询与性能优化实战

在Unity游戏开发中,高效管理和查询场景对象是提升开发效率和性能的关键。通过将场景层级结构视为数据集合,开发者可以运用声明式查询原理,简化复杂对象筛选逻辑。这一技术价值在于大幅提升代码可读性与维护性,尤其适用于UI管理、动态对象筛选和编辑器工具开发等应用场景。本文结合Unity性能优化和C# LINQ技术,深入解析如何利用LINQ to GameObject实现高效组件筛选与层级遍历,帮助开发者避免常见陷阱,自然收敛到提升项目代码质量与开发体验的核心主题。

weixin_30279315的博客 337

C# LINQ where与select的工业级数据流建模

LINQ 的 where 和 select 不是简单的集合操作语法,而是 .NET 数据流编排的核心原语。其本质涉及 IQueryable/IEnumerable/IAsyncEnumerable 三层执行策略,直接影响数据库查询下推、内存遍历开销与异步流处理时机。在工业上位机、Modbus 数据采集、实时监控等场景中,错误的物化时机(如过早 ToList)会导致 CPU 飙升、UI 卡顿与 GC 压力激增;而合理的延迟投影与状态感知过滤(如滑动窗口告警),则能实现毫秒级响应与低内存占用。本文聚焦 C# 工

weixin_34396902的博客 1032

C#中非IEnumerable集合如何使用LINQ:四种实战方案对比

LINQ扩展方法本质上是面向IEnumerable<T>或IQueryable<T>的契约式工具,其调用依赖编译期类型匹配而非运行时行为。当自定义集合(如DDD聚合根、DTO容器)未实现IEnumerable<T>时,.Where()等方法即失效——这并非语法限制,而是类型系统对数据可枚举性的显式要求。理解这一原理,才能合理选择适配路径:显式转换适用于临时调试与内存计算;隐式转换虽简洁但易触发序列化副作用;扩展方法注入在封装性与性能间取得最佳平衡,支持内联优化且零内存分配;查询对象模式则面向复杂条件组合与C

SailingAptech的专栏 462

C# Cast<T>原理与实战:LINQ泛型桥接核心技术

Cast<T>是.NET中实现非泛型集合向IEnumerable<T>安全转换的核心机制,其本质并非简单类型转换,而是通过运行时类型校验建立泛型契约,为LINQ链式调用提供必需的接口准入。它基于赋值兼容性(而非隐式转换)执行严格拆箱与强制转换,在WinForms控件集合、WPF ItemsControl、DataTable.Rows等典型场景中承担着‘类型桥梁’的关键角色。理解Cast<T>与OfType<T>的语义差异、掌握装箱/拆箱限制、规避动态集合遍历陷阱,是保障桌面应用数据操作健壮性的基础能力。

as2886089的博客 429

Unity对象遍历优化:LINQ查询与缓存机制的性能实践

在Unity游戏开发中,对象遍历是常见的性能瓶颈,尤其是在场景复杂度高、GameObject数量庞大的情况下。传统方法如GameObject.Find和递归遍历在频繁调用时会产生显著的性能开销和GC Alloc,影响游戏帧率。LINQ(Language Integrated Query)作为一种声明式查询技术,通过延迟执行和链式操作,能够以更优雅、意图更清晰的方式处理集合数据。其技术价值在于将复杂的遍历逻辑抽象为简洁的查询表达式,并结合缓存机制,可以大幅减少运行时搜索开销。在Unity开发中,通过手动维护对

weixin_30367873的博客 350

langchain入门学习笔记

langchain快速入门

1730

深入理解C# foreach与IEnumerable延迟执行机制

IEnumerable<T> 是 .NET 中表示可枚举序列的核心接口,其本质并非数据容器,而是支持按需供给、状态驱动的迭代契约。它通过 IEnumerator<T> 实现延迟执行(Deferred Execution)——仅在消费时触发计算,配合 yield 关键字自动生成状态机,实现高效、内存友好的流式处理。这一机制是 LINQ to Objects 组合查询、性能优化与避免重复执行的基础,广泛应用于大数据遍历、文件流读取、数据库查询封装等场景。理解其原理,才能规避 foreach 修改失效、断点不触发

dingguayi7025的博客 937

关键词‖旋变传感器

旋转变压器(以下简称旋变)安装在永磁同步驱动电机的非传动端,其作用是检测转子的位置和速度。目前,通常采采用结构简单、坚固耐用、环境适应性好的磁阻式旋变作为位置传感器。

m0_72345077的博客 2147

SAP采购含税价转换的底层逻辑解析:ABAP例程如何实现价税分离计算

本文深入解析SAP系统中采购含税价与不含税价的转换机制,重点介绍VOFM例程和ABAP代码实现价税分离计算的方法。通过详细讲解数学原理、税率体系及SAP定价引擎架构,为开发人员提供完整的解决方案,帮助提升采购业务中的价格处理效率和准确性。

weixin_29237635的博客 450

C# LINQ Zip详解:按索引顺序配对两个集合

在C#开发中,经常遇到两个集合顺序一一对应、需要按索引位置合并的场景,例如传感器数据采集、Excel导入或报表生成。传统方法依赖for循环和下标随机访问,但面对IEnumerable或惰性序列时显得笨拙。LINQ的Zip操作符就像一条拉链,按位置将两个序列的元素配对,返回较短集合长度,并支持延迟执行与链式组合。它天然适用于任意IEnumerable<T>,避免了索引越界风险,同时简化了代码。Zip不仅能合并两个列表,配合Aggregate、Skip或无限序列还能实现差值计算、编号生成等高效操作。文中详解了三

weixin_34413103的博客 136

CAD的.dwg文件导入 ArcGIS:高程分析、坡度分析、坡向分析

CAD的.dwg文件导入 ArcGIS,再进行高程分析、坡度分析、坡向分析。

My_Echo_yM的博客 7234

C# LINQ中Where与Select的工程化实践指南

LINQ中的Where和Select是.NET数据处理的核心操作符,本质是延迟执行的函数式数据流组件:Where实现条件过滤与节流控制,Select完成投影变换与结构重构。其原理根植于IEnumerable接口、委托链与yield return机制,技术价值在于解耦数据获取、过滤与转换逻辑,支撑高频采集、实时UI刷新、PLC上位机通信等典型工业场景。在西门子1200 PLC数据采集、NModbus4寄存器解析及WPF绑定中,合理运用Where条件短路、Select惰性求值与闭包规避,可显著降低GC压力、避免

weixin_34320159的博客 248

硬件原理图:从软件思维到硬件接口的嵌入式开发破局指南

本文为软件开发者提供了读懂硬件原理图的嵌入式开发破局指南。文章将硬件原理图类比为“硬件系统的架构图”,引导读者将软件API调用思维迁移到硬件接口理解上,详细解析了电阻、电容、二极管等常见元器件的“硬件API”功能与选型逻辑,并通过实战电路拆解,阐述了从原理图分析到驱动代码编写的完整思维链条,帮助开发者建立软硬件协同的系统级视角。

lg888的博客 493

48、住宅抵押贷款支持证券的定价、风险评估与结构化设计

本文深入探讨了住宅抵押贷款支持证券(RMBS)的定价、风险评估与结构化设计。内容涵盖提高定价准确性的方差缩减方法,如准蒙特卡罗序列的应用;分析RMBS面临的利率风险、信用风险和模型风险,并提出相应的度量与应对策略;介绍利用动态规划优化CMO分层结构以最大化发行利润的方法。同时总结了RMBS的基本类型、定价流程及市场发展趋势,为投资者和发行人提供全面的决策支持。

quiet的专栏 154

Unity开发中利用LINQ实现高效GameObject查询与遍历优化

在Unity游戏开发中,对象查询与遍历是基础且高频的操作,传统方法如GameObject.Find和手动循环常导致代码冗长和性能问题。其原理在于将场景层级结构视为可查询的数据集合,通过声明式编程替代过程式逻辑。这一技术价值在于大幅提升代码可读性、开发效率和可维护性,同时借助延迟执行等特性优化性能。应用场景广泛覆盖UI管理、动态对象筛选、游戏状态控制等。本文聚焦LINQ to GameObject范式,通过扩展方法封装,结合热词如性能优化和GC(垃圾回收)管理,为开发者提供一套清晰、高性能的层级遍历解决方案。

ctpaknc9526的博客 364

【DRAM存储器五十六】LPDDR5介绍--WCK2CK Leveling和Read gate training

简述LPDDR5 WCK2CK leveling和read gate traning基本原理与操作步骤

highman110的博客 8787
上一篇: 什么!?Unity的SetTrigger(string name)不能用了?
下一篇: C# 谁是短字符串拼接之王
ZZHSourceCode
博客等级 码龄9年 8粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值