恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

别再只会 new List() 了!C#15 的 with(capacity:) 到底香在哪?

  • 首页
  • 资讯中心
  • /
  • 别再只会 new List() 了!C#15 的 with(capacity:) 到底香在哪?

相关资讯

快速恢复SJ MOSFET如何破解PFC效率瓶颈:MDmesh DM9实战解析 2026/8/29 19:00:01
iOS自定义相机实战:AVFoundation曝光补偿与实时亮度分析 2026/8/29 19:00:01
AI Agent安全事故缘何潜伏?权限失控、审计缺位与工程防线 2026/8/29 18:55:01

最新资讯

MATLAB优化工具箱实战:从标准规划问题到求解器深度解析
AI爬虫打挂Bugzilla?Nginx+fail2ban+限流实战防护指南
AI爬虫流量压垮Gentoo Bugzilla:事件复盘与防护指南
基于生成式模型的Agentic空间认知评估框架解析
AI实验室落地指南:从数据闭环到实验自动化
机器学习公平性评估:Disparate Impact 为何不能只看一个比率

今日推荐

云计算SPI三类服务模式是逐层抽象的关系:IaaS提供最底层的硬件资源,PaaS在IaaS基础上封装了开发运行环境,SaaS则进一步封装为可直接使用的软件
最新稳定版(Python 3.14):这是目前官方推荐的最新稳定版本。作为最后一个采用传统“3.x”命名的版本
etc目录下的profile.d文件目录设置环境变量和全局脚本shell

本周热门

Nextcloud 桌面客户端:把同步交给它,你只管改文件
如何将 HTML 转成 Word 文档且格式不丢失?html-to-docx 使用教程
Anki 批量操作卡片完整指南:一次搞定上千张,不再逐张修改

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

别再只会 new List() 了!C#15 的 with(capacity:) 到底香在哪?

发布时间:2026/8/29 19:00:01
别再只会 new List() 了!C#15 的 with(capacity:) 到底香在哪? 最近小编研究了C# 15的一批新语法翻到集合表达式时突然被with(capacity:)这个不起眼的修饰符勾住了。说起来有点不好意思写 .NET 这么多年我一直是能用就行派Listint items new();然后闭眼往循环里Add。直到上周做数据处理往 List 里塞了几百万条记录肉眼可见地卡顿我才认真把预分配这三个字掰开揉碎研究了一遍。先别急着写代码List的成长烦恼你了解吗ListT的本质是一个会自动长大的数组。它内部维护一块连续内存_items数组不够用时就扩容。扩容策略简单粗暴容量翻倍——0 → 4 → 8 → 16 → 32 → …… 一直翻到装得下为止。每次扩容要干两件事重新申请一块更大的内存。把旧数组的所有元素逐个拷贝过去。// ListT 扩容的真实逻辑源码简化版 private void Grow(int capacity) { // 新容量 旧容量 * 2空数组时下限是 4 int newCapacity _items.Length 0 ? 4 : 2 * _items.Length; // 翻倍还不够装直接用需要的容量 if ((uint)newCapacity (uint)capacity) newCapacity capacity; // 新数组 老数据全量拷贝一步到位 Array.Resize(ref _items, newCapacity); }以 10 万个 int 为例无预分配时容量要经历 4、8、16、……、65536、131072一共 16 次扩容累计拷贝约 13 万个元素。单看数据量不大但请注意131072 × 4 字节 512KB已经超过 85KB 的大对象堆LOH阈值。也就是说扩容到后期申请的全是大数组频繁分配 拷贝会造成 LOH 碎片和额外的 GC 压力数据量再大几倍卡顿就来了。这里有个新手极易踩坑的地方很多文章只说翻倍扩容却没人提 LOH当集合元素超过约 2 万个 int或同等字节数时底层数组就进了大对象堆反复扩容的代价比你想的高得多。三种写法直接上实测我写了个小实验往 List 里塞 10 万个元素分别用三种方式创建。写法一祖传 new() 无脑 Add// 零预分配全靠扩容硬扛 Listint items new(); for (int i 0; i 100_000; i) items.Add(i);写法二老派的 new(capacity) 预分配// 提前告诉 List 我要 10 万个避免中途扩容 Listint items new(100_000); for (int i 0; i 100_000; i) items.Add(i);写法三C# 15 的 with(capacity:) 集合表达式// 集合表达式 with(capacity:) 预分配 展开运算符填充 Listint items [with(capacity: 100_000), ..Enumerable.Range(0, 100_000)];完整测速代码如下using System.Diagnostics; const int Size 100_000; // 教训来自我第一次跑出来的假数据 // 毫秒精度 无预热 固定顺序结果完全失真 var sw Stopwatch.StartNew(); // 先热热身把 JIT 编译和启动开销排除在外 Warmup(); // 写法一无预分配 sw.Restart(); Listint noCap new(); for (int i 0; i Size; i) noCap.Add(i); Console.WriteLine($无预分配 : {sw.ElapsedTicks / 10f:F1} us); // 写法二传统容量预分配 sw.Restart(); Listint old new(Size); for (int i 0; i Size; i) old.Add(i); Console.WriteLine($new(capacity) 预分配 : {sw.ElapsedTicks / 10f:F1} us); // 写法三C# 15 with(capacity:) sw.Restart(); Listint modern [with(capacity: Size), ..Enumerable.Range(0, Size)]; Console.WriteLine($with(capacity:) : {sw.ElapsedTicks / 10f:F1} us); static void Warmup() { var list new Listint(); for (int i 0; i Size; i) list.Add(i); }结果我跑了好几轮取的是中位数new()无脑版最慢new(Size)和with(capacity:)速度接近都是无预分配版的2 倍以上with() 版本在部分轮次略快但差距基本在误差范围内。先泼盆冷水第一次实测我差点被数据骗了说实话第一次跑的时候我的结果完美得可疑——with() 版本稳压 50% 以上。后来一查才发现问题全出在测量方式上毫秒精度太粗ElapsedMilliseconds是整数毫秒10 万元素这种量级本来就几毫秒误差直接把真实差距淹没了。没有预热第一段代码吃满 JIT 编译和启动开销谁先跑谁吃亏。固定执行顺序执行顺序本身就是个隐藏变量。这也是很多性能帖子的通病结论不是代码跑出来的是测量方式跑出来的。我后来改成预热 乱序 多轮取中位数这才看到真实差距——预分配确实赢但赢在少扩容而不是语法本身。with(capacity:) 到底香在哪我的答案是可读性 上限保护先说性能new(Size)和[with(capacity: Size), ..]本质都在做同一件事——提前确定底层数组大小省掉扩容。二者是同一个量级谁也别想碾压谁。那新语法价值在哪我认为有三点声明式表达集合表达式把建集合 定容量 填充压成一行语义自文档化读代码的人一眼就知道你要干什么。容量上限保护with(capacity:)让你在填充前就把规模预期写死从写法上杜绝忘了预分配。生态统一C# 15 之后集合初始化越来越值语义配合 spread 运算符..拼装数据流的代码能写得非常顺。适用场景我的判断明确知道规模批量灌数据、从数据库读 N 条→ 必须预分配热点路径高频创建集合→ 预分配能明显降 GC不知道规模→ 别硬猜new()EnsureCapacity按需兜底。避坑清单预分配不是无脑抄容量别拍脑袋with(capacity: 1_000_000)但只塞 10 条纯属浪费内存。预分配的是内存不是保险。大集合留意 LOH超过 85KB 的数组进大对象堆频繁扩容更容易碎片化。能一次到位就一次到位。测性能先讲方法论预热、乱序、多轮、取中位数别拿ElapsedMilliseconds唬自己。注意版本要求with(capacity:)是 C# 15 语法需要 .NET 10 及以上 SDK生产环境没升级就老老实实用new(capacity)。总结List 预分配这事说到底是数组扩容成本和内存占用的博弈。new()不是不能用而是你要知道它在背后默默扩容了 16 次new(capacity)是性价比最高的传统解C# 15 的with(capacity:)则是把这件事做成了声明式语法代码更干净心智负担更小。大家对这个with的这个新语法有什么看法欢迎留言讨论。参考https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-15#collection-expression-arguments

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号