字符串插值需同时使用$和{},缺一不可;支持内联格式化但格式符须紧邻表达式;对null需安全处理;高频场景宜用stringbuilder避免gc压力;跨平台时需注意cultureinvariant处理。

字符串插值语法写错:$ 和 {} 缺一不可
字符串插值不是简单加个 $ 就完事。漏掉 $ 前缀,编译器会直接报错 CS1056: Unexpected character '$';漏掉大括号 {},比如写成 $"Hello {name}" 是对的,但写成 $"Hello name" 就只是普通字符串,变量名不会被替换。
常见错误场景:
- 在旧版 C#(
是否 ≥ 6 - 在字符串里嵌套引号时没转义:
$"Name: \"{name}\""或用逐字字符串$@"Name: ""{name}""" - 表达式太复杂导致可读性崩坏,比如
$"Total: {items?.Sum(x => x.Price * x.Count) ?? 0:C}",建议提前计算再插值
格式化与类型转换:插值里直接写格式说明符
插值支持内联格式化,无需额外调用 ToString("F2") 或 string.Format。但格式说明符必须紧跟在表达式后、右大括号前,中间不能有空格。
实操要点:
- 数字格式:
$"{price:C2}"输出带货币符号和两位小数,$"{value:P1}"输出百分比(如12.3%) - 日期格式:
$"{DateTime.Now:yyyy-MM-dd HH:mm}"—— 注意冒号是分隔符,不是字符串的一部分 - 对 null 值做安全处理:
$"{user?.Name ?? "Anonymous"}",但??后不能跟格式说明符;若需格式化默认值,得拆开:$"{(user?.Name ?? "Anonymous"):G}" - 自定义类型要生效,需重载
ToString()或实现IFormattable
性能敏感场景:别在循环里拼接大量插值字符串
每次插值都会隐式创建 string,底层调用 string.Format 或构造器。在高频循环(如日志批量写入、网络包组装)中反复使用,可能触发 GC 压力。
替代方案:
- 用
StringBuilder预分配容量:var sb = new StringBuilder(256); sb.Append($"ID:{id}, Name:{name}"); - 若只是拼接固定字段,考虑用常量 +
+连接(编译期优化),但仅限于全字面量或已知不变的变量 - 避免在插值中调用耗时方法:
$"Result: {ExpensiveCalculation()}"会每次执行,不如先赋值再插值 - .NET 6+ 中,
string.Create可用于极致性能场景,但需配合Span<char></char>,适用面窄,一般项目不推荐过早优化
跨平台与本地化:插值本身不处理文化差异
字符串插值默认使用当前线程的 CultureInfo.CurrentCulture,这意味着 $"{1234.56:C}" 在美国显示为 $1,234.56,在德国可能是 1.234,56 €。如果你的程序要输出固定格式(比如 API 返回 JSON),这会出问题。
关键控制点:
- 强制指定文化:
$"{value:C2}".ToString(CultureInfo.InvariantCulture)不行——插值已完成,应改用string.Format(CultureInfo.InvariantCulture, "{0:C2}", value) - 更稳妥的做法:插值前统一转成 invariant 字符串:
$"Price: {price.ToString("C2", CultureInfo.InvariantCulture)}" - ASP.NET Core Web API 默认序列化走
System.Text.Json,它不走插值,所以接口返回数值字段时不受影响;但手动拼接响应体(如ContentResult)就得自己管文化
最容易被忽略的是日志场景:用插值记录数值时,如果日志分析系统依赖小数点为点号,而服务器 Culture 是德语,就可能导致解析失败。











