字符串插值用字面文本和表达式拼出一个字符串。在字面量前加 $,把任意 C# 表达式放进花括号,它的值就会被转换成文本插入进去:
输出:
Hello, Maya!
3 items at 4.5 = 13.5
Name has 4 letters, upper: MAYA
Free shipping: yes
插值是 C# 6 引入的。编译器会把它转换成 string.Format 或 string.Concat 调用(从 C# 10 起,会转换成更高效的处理程序代码),所以它并不比手动拼接字符串慢。
最后一行中的条件表达式需要加括号。在插值的花括号里,冒号表示格式说明符的开始,所以不加括号的 {x > 10 ? "yes" : "no"} 会导致编译错误。
格式说明符
在表达式后面加一个冒号和格式字符串,就能控制值的写法。同样的格式字符串也适用于 ToString("...") 和 string.Format。
输出:
1234567.89
1,234,567.89
1,234,568
00042
FF
00ff
1.23E+006
0.813
81.3%
1,234,567.89
007.5
3.1
标准格式代码,每个后面都可以跟一个精度数字:
| 代码 | 名称 | 示例 | 结果 |
|---|---|---|---|
F 或 F2 | 定点 | {3.14159:F2} | 3.14 |
N 或 N0 | 带分组分隔符的数字 | {1234.56:N0} | 1,235 |
C | 货币(区域性的符号和格式) | en-US 下的 {9.5:C} | $9.50 |
D5 | 用零补齐的整数 | {42:D5} | 00042 |
X、x | 十六进制 | {255:X} | FF |
E2 | 科学计数法 | {1234.5:E2} | 1.23E+003 |
P1 | 百分比(乘以 100) | en-US 下的 {0.256:P1} | 25.6% |
G | 常规(最短形式) | {2.50m:G} | 2.50 |
R | 往返(double) | {0.1:R} | 0.1 |
自定义格式由占位符组成:0 是始终显示的数字位,# 是仅在有意义时才显示的数字位,. 是小数点,数字中间的 , 启用分组分隔符,% 会乘以 100。"0.##" 最多显示两位小数并去掉末尾的零;"#,##0.00" 是经典的会计格式。
所有数字格式化都会对显示的值进行四舍五入,变量本身不变。当值正好处于中间(2.25 保留一位小数)时,不同的运行时和类型对这种平局的舍入可能不同,所以如果规则很重要,先用 Math.Round(value, 1, MidpointRounding.AwayFromZero) 显式舍入,再进行格式化。
插值中的日期
DateTime 值以同样的方式接受日期格式字符串:
输出:
2026-09-24
24/09/2026 16:05
Thu, Sep 24
Shipped at 16:05 on Thursday
ETA 02:10
2.2 hours
TimeSpan 的自定义格式要求用反斜杠转义字面字符,在普通字符串字面量里写作 \\:。完整的日期代码列表(yyyy、MM、HH、tt...)以及大家常犯的错误(mm 是分钟,MM 是月份)见 DateTime 格式。
对齐与补齐
表达式后面的逗号设置最小字段宽度。正数表示右对齐,负数表示左对齐。和格式结合使用,就能在纯文本中把表格排整齐:
输出:
Item | Price| Sold
----------------------------
Espresso | 2.40| 118
Latte | 3.60| 64
Hot chocolate | 4.25| 9
语法是 {expression,alignment:format}:先写对齐,再写格式。比宽度长的值不会被截断,而是把这一行剩下的内容往后推。在插值之外,PadLeft 和 PadRight 也能实现同样的补齐。
转义花括号
要输出字面的花括号,就写两次:{{ 和 }}。输出 JSON、CSS 或代码时经常会用到:
输出:
{ "id": 42, "name": "Ana" }
Set literal: {1, 2, 3}
{42}
像这样手写 JSON 用来快速打一行日志没问题;真正的 JSON 请使用序列化器,它能正确处理 name 里的引号和特殊字符。
string.Format 与复合格式
在 C# 6 之前,格式化靠 string.Format 完成,它接受带编号的占位符和一组参数。Console.WriteLine、StringBuilder.AppendFormat 和 TextWriter.Write 也接受同样的复合格式语法:
输出:
Notebook x4: 14.00
Notebook | 3.50
echo echo !
Dear Leo, your order #000731 has shipped.
在代码中优先使用插值:值就写在它出现的位置,占位符不可能指向错误的参数。当模板本身是数据时,比如从资源文件加载的翻译消息,string.Format 仍然是合适的工具。占位符索引没有对应的参数(只有两个参数却写了 {2})时,会在运行时抛出 FormatException。
区域性:控制分隔符和货币
插值、ToString 和 string.Format 默认都使用线程的当前区域性。在设置为德语的机器上,{1234.5:N2} 得到 1.234,50;在美国则得到 1,234.50。货币格式 C 使用区域性的货币符号。要显式选择区域性,就把插值字符串捕获为 FormattableString,再用一个提供程序来格式化:
输出:
Total: 1,234.50
Total: 1.234,50
$1,234.50
1.234,50
1234.5,0.75
给人读的文本使用用户的区域性,给其他程序读的内容使用 CultureInfo.InvariantCulture。在德语机器上用当前区域性写出的 CSV,数字中带有逗号,换个地方就无法读取。在 .NET 6 及更高版本中,string.Create(CultureInfo.InvariantCulture, $"...") 的效果与 FormattableString.Invariant 相同,但不会创建中间对象。
逐字插值字符串和原始插值字符串
$ 可以和 @ 组合成逐字插值字符串:反斜杠按字面处理,字符串可以跨多行。C# 8 及更高版本接受任意顺序($@ 或 @$);C# 6 和 7 要求写 $@:
输出:
C:\Users\ana\Reports\2026\summary.txt
Report for ana
Year: 2026
C# 11 新增了原始插值字符串。用一个 $ 时,花括号照常表示表达式。用 $$ 时,单个花括号是字面字符,表达式需要两个花括号,这让 JSON 和代码模板更易读:
// C# 11 and later
int id = 42;
string name = "Ana";
string json = $$"""
{
"id": {{id}},
"name": "{{name}}"
}
""";
C# 11 还允许在插值的花括号内换行,所以长表达式或 switch 表达式可以拆成多行来写。
常见错误
- 忘了写
$。"Total: {total}"会原样输出花括号,编译器不会给出警告。 - 花括号里的三元表达式没加括号:冒号会被当成格式分隔符。
- 用当前区域性格式化给机器读的输出。 小数逗号会破坏 CSV、JSON 和 SQL。请使用固定区域性。
- 金额用不带格式的
ToString()。2.5m会输出2.5,而不是2.50。请用F2、N2或C。 - 在循环里用插值构建大字符串。 每次迭代都会创建一个新字符串;请使用 StringBuilder 或
string.Join。
常见问题
C# 字符串插值是什么?
一种以 $ 开头的字符串字面量,花括号里的表达式会被求值并插入其中:$"Total: {price * qty}"。它在 C# 6 中加入,取代了大多数 string.Format 和 + 拼接的用法。花括号里可以放任何表达式,包括方法调用和属性访问。
C# 中如何把数字格式化为保留 2 位小数?
在冒号后面加格式说明符:$"{price:F2}" 输出小数点后 2 位,$"{price:N2}" 效果相同,但带千位分隔符。在插值之外,同样的格式代码也可以用于 price.ToString("F2")。两者都只是为了显示而四舍五入,不会改变值本身。
C# 插值字符串中如何转义花括号?
写两次:{{ 输出 {,}} 输出 }。例如 $"{{ \"id\": {id} }}" 输出 { "id": 42 }。在 C# 11 的原始插值字符串中,也可以用 $$ 开头,这样单个花括号就是字面字符,而 {{expr}} 表示表达式。
string.Format 和字符串插值有什么区别?
它们用同样的格式代码得到同样的结果。string.Format("{0} costs {1:F2}", name, price) 按位置引用参数;$"{name} costs {price:F2}" 把表达式直接写在字符串里,更易读,也不会弄错参数顺序。当格式字符串本身来自资源文件或数据库时,仍然需要 string.Format。
为什么插值出来的数字用逗号而不是小数点?
插值使用当前线程的区域性来格式化,而很多区域性用逗号作为小数分隔符。对于给程序读取的输出(文件、JSON、URL),请用固定区域性格式化:FormattableString.Invariant($"{value:F2}"),或在 .NET 6 及更高版本中使用 string.Create(CultureInfo.InvariantCulture, $"...")。