C#:数组与列表的差异

C# 数组(Array)是‌固定长度‌的连续内存块,适合‌已知规模、高频只读 ‌场景;泛型列表(List<T>)是‌动态扩容 ‌的封装结构,适合‌规模不确定、需频繁增删‌场景。两者索引访问均为 O(1),但底层开销与内存行为差异显著。

关键差异对比

表格

维度 数组 (T[]) 列表 (List<T>)
‌长度可变性‌ ❌ 创建后不可变(需 Array.Resize 重建) ✅ 自动扩容(默认策略:容量不足时翻倍)
‌内存布局‌ 纯连续内存,无额外字段,GC 压力小 内部含数组 + Count/Capacity 字段;未设容量时易产生冗余空间
‌访问性能‌ 极快(IL 指令 ldelem 直接寻址,缓存友好) 略慢(含方法调用、边界检查;Debug 模式更明显)
‌增删操作‌ 不支持原生增删;中间插入/删除需手动移动元素(O(n)) Add() 均摊 O(1)(尾部);Insert/RemoveAt 为 O(n)(需移位)
‌功能丰富度‌ 基础操作(索引、Length、Array.Sort 等) 丰富方法(Add/Remove/Find/Contains/LINQ 兼容等)
‌类型安全‌ 泛型原生支持,值类型零装箱 泛型实现,值类型零装箱(优于非泛型 ArrayList)
‌典型场景‌ 图像像素缓冲、配置常量表、高频遍历固定数据集 用户输入收集、运行时对象列表、迭代开发中数据量不确定场景

性能与优化要点

  • ‌内存占用 ‌:未预设容量的 List<T> 因多次扩容,峰值内存可达同规模数组的‌5~10 倍 ‌;建议用 new List<T>(expectedSize) 预分配。
  • ‌GC 影响 ‌:短生命周期大 List 易触发 Gen0 GC;局部小数组常被 JIT 优化至栈上(配合 Span<T> 可进一步零分配)。
  • ‌多维支持 ‌:数组原生支持多维(int[,]);List<T> 仅一维,嵌套列表效率低且内存不连续。
  • ‌接口抽象 ‌:对外暴露集合时优先用 IReadOnlyList<T> 或 Span<T>(.NET Core 2.1+),避免泄露具体实现。

选择决策流

  1. 数据量是否‌创建时已知且永不变更 ‌? → ‌是‌:用数组
  2. 是否需‌频繁在中间插入/删除 ‌? → ‌是 ‌:评估 LinkedList<T> 或保留 List<T>(小数据量可接受 O(n))
  3. 是否需‌动态增长 + 丰富操作 + LINQ ‌? → ‌是 ‌:用 List<T>(务必预设容量)
  4. 极端性能敏感(如游戏帧循环、高频交易)且数据固定? → ‌优先数组 ‌,必要时结合 Span<T> 避免拷贝。

注:Array.Resize 本质是新建数组 + 复制,非真正"扩容";避免在高频路径中反复创建集合实例。

相关推荐
2501_944521597 小时前
Ramda 跨端三方库仓颉适配全流程
开发语言·javascript·flutter·php
行思理7 小时前
go语言学习难度及适合学习的人群
开发语言·学习·golang
wangchunyu1149 小时前
JAVA CompletableFuture异步编程实战
java·开发语言·python
程序 代码狂人10 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
meiying883811 小时前
快递单号批量查询Python脚本:从手动到自动化的完整实现
开发语言·python·自动化
@大迁世界12 小时前
告别 Go,拥抱 Rust
开发语言·golang·rust
SEO_juper12 小时前
Node.js 重定向链检测工具:301 跳了几跳、有没有成环,一次看清
xml·开发语言·python·node.js·json·bash
学逆向的12 小时前
C 指针常量与常量指针
c语言·开发语言·网络安全
低调滴开发13 小时前
3 行代码写崩一个函数?切片才是 Rust 字符串处理的正确姿势
开发语言·后端·rust
CodeYp201913 小时前
第15讲:二叉搜索树
开发语言·c++·二叉搜索树