C#字符串拼接优先用$插值字符串,简单场景用string.Concat(),高频循环必须用StringBuilder;避免无脑+连接,尤其循环中。

直接说结论:C# 拼接字符串优先用 $" 插值字符串,简单场景用 string.Concat(),高频循环拼接必须用 StringBuilder;别再无脑用 + 连接多个变量,尤其在循环里。
什么时候该用 $" 插值而不是 +?
插值不是语法糖的“炫技”,它在编译期就被优化成 string.Format() 或更优的内联处理,可读性和性能都更好。而 + 在涉及多个非字面量时会隐式调用多次 string.Concat(),生成临时字符串对象。
- 推荐:
$"用户 {name} 登录时间 {DateTime.Now:HH:mm}"—— 清晰、类型安全、支持格式化 - 不推荐:
"用户 " + name + " 登录时间 " + DateTime.Now.ToString("HH:mm")—— 多次装箱、易错、难维护 - 注意:
$后不能跟换行(除非用逐字字符串@$"),且大括号内不能直接写未声明变量,比如${x?.Length ?? 0}合法,${x.Length}可能抛NullReferenceException
string.Concat() 和 string.Join() 的分工边界
Concat() 是纯拼接,不做分隔;Join() 是带分隔符的聚合,底层都避免了中间字符串分配,比 + 更可控。
- 拼数组/集合无分隔:用
string.Concat(strArray),比strArray.Aggregate((a,b) => a+b)快且内存友好 - 需要逗号分隔:用
string.Join(", ", list),它内部做了长度预估,不会反复扩容 - 错误用法:
string.Join("", new[] { "a", null, "c" })会抛ArgumentNullException;要容错得先过滤或用?.ToString() ?? ""
为什么循环中拼字符串必须用 StringBuilder?
假设循环 1000 次,每次拼一个短字符串:+ 会产生约 O(n²) 次内存拷贝(因为字符串不可变),而 StringBuilder 默认容量 16,自动倍增扩容,最终只分配几次大块内存。
- 初始化建议:
new StringBuilder(2048)—— 如果能预估总长,直接设容量,避免多次Array.Copy - 追加内容用
.Append()或.AppendLine(),别混用.ToString() + "xxx" - 常见坑:
sb.Append(x.ToString()).Append(y.ToString())中如果x或y是null,ToString()不会崩,但语义可能不对;更稳妥是sb.Append(x?.ToString() ?? "")
Span 和 Memory 能替代拼接吗?
它们不用于“拼接”,而是用于零分配的字符串切片和写入——适合高性能日志、协议解析等场景,但要求目标缓冲区已存在且大小可控。
- 典型用途:
var buffer = stackalloc char[512]; var span = buffer.AsSpan(); span[..4].CopyTo(destination); - 不能直接拼:
span本身不增长,也不管理内存生命周期;想“拼”就得自己算偏移、检查长度,出错就是IndexOutOfRangeException - 适用前提:你知道所有片段长度之和 ≤ 缓冲区大小,且不需要返回
string(否则还得调ToString()触发一次分配)
真正难的不是选哪个 API,而是判断「这个拼接是否在热路径里」以及「结果会不会被长期持有」。很多性能问题不是拼法错了,是根本没必要拼——比如日志模板可以预编译,SQL 拼接应该交给参数化查询。











