优先用 Array.Copy 手动拼接;Concat() 适合只读遍历或链式处理,但反复调用再 ToArray() 更慢更耗内存,3个以上数组应避免链式 Concat,改用 Enumerable.Concat 或 Array.Copy;Array.Copy 可控稳定、零中间对象,需预分配目标数组并注意 offset 和 length 参数。

直接说结论:要合并多个数组且关注性能,优先用 Array.Copy 手动拼接;Concat() 适合只读遍历或链式处理,但反复调用再 ToArray() 反而更慢、更耗内存。
Concat() 看似简单,但多次链式调用会拖垮性能
很多人写 a.Concat(b).Concat(c).Concat(d).ToArray(),以为只是“多连几次”,实际会生成嵌套迭代器——每次遍历都触发一层委托调用,深度越深开销越大。尤其当数组数量超过 4 个、单个长度过万时,这种写法比一次性分配+复制慢 2–3 倍。
常见错误现象:InvalidOperationException 或 GC 压力陡增,不是因为数据错,而是迭代器状态机堆栈太深。
- 只合并两个数组?
Concat()+ToArray()没问题 - 合并 3 个以上?别链式调用,改用
Enumerable.Concat(IEnumerable<t>[])</t>(需自行封装)或直接切到Array.Copy - 类型必须一致:
int[]和long[]不能混用,编译报错,不自动转换
Array.Copy() 是可控、稳定、CPU 友好的选择
它不依赖 LINQ、不产生中间对象、无装箱、无迭代器,纯内存块搬运。只要提前算好总长,就能一次分配、两次(或多轮)复制。
关键注意点:
- 目标数组必须
new T[totalLength],否则抛ArgumentException:“源数组中复制的元素数大于目标数组中从索引开始的可用空间” -
Array.Copy(source, 0, dest, offset, length)的第四个参数是offset(目标起始位置),不是固定写0;第五个参数是本次复制的length,不是源数组.Length(虽然常等价) - 引用类型数组(如
string[])必须用Array.Copy;值类型可考虑Buffer.BlockCopy(按字节拷贝,更快但需确保元素大小对齐)
.NET 6+ 的 MemoryExtensions.Concat() 适合 Span 场景,但有硬限制
如果你操作的是栈上数组(stackalloc int[100])、或在 hot path 中高频小规模拼接,ReadOnlySpan<t>.Concat()</t> 是唯一真正零分配的方式。
但它不接受普通数组,必须显式转成 Span:
int[] a = {1, 2};
int[] b = {3, 4};
ReadOnlySpan<int> combined = a.AsSpan().Concat(b.AsSpan()); // ✅
// int[] c = combined.ToArray(); // ❌ 编译失败:Span 不能直接 ToArray
限制很实在:
- 不能跨方法返回
Span<t></t>,生命周期绑定原始数组作用域 - 不支持引用类型数组拼接(
string[].AsSpan()编译不过) - 返回的是
ReadOnlySpan<t></t>,不能修改,也不能当T[]直接用
最易被忽略的一点:无论选哪种方式,只要最终要一个完整 T[],就逃不开一次堆分配。如果数组总长 > 85,000 字节,会进大对象堆(LOH),影响 GC 行为——这不是方法问题,是 .NET 内存模型决定的,得提前评估。



















