原始字符串字面量"""不是增强版@"",而是完全独立语法:不解析转义、允许自然换行、可嵌入未转义双引号;但结尾"""必须独占一行且无任何字符(含空格/tab),缩进须严格对齐(空格与tab不可混用),插值时$"""{x}易误解析,输出字面"""需用六引号包裹。

原始字符串字面量(""")不是“更高级的 @""”,而是完全不同的语法机制:它不解析任何转义、允许自然换行、支持直接嵌入未转义双引号,但对结尾位置和缩进极其敏感——写错一行就编译失败。
为什么 """ 会报错 “Unexpected character '"""'”
这是最常见的编译错误,根本原因不是内容写错了,而是结尾的 """ 没被识别为终止符。
- 结尾
"""必须独占一行,且该行**不能有任何其他字符**(包括空格、制表符、注释) - 开头
"""后如果直接换行,那第一行内容行的缩进必须与结尾行对齐,否则编译器无法确定“最小公共前导空白”从哪算起 - 混用空格和制表符会导致剪裁失败——比如结尾行用 4 个空格,而内容行用了 2 个空格 + 1 个制表符(即使视觉对齐),也会触发错误
- 最稳妥写法:开头
"""放行首,所有内容左对齐,结尾"""也放行首
$""" 插值时大括号 { 紧贴引号的坑
当插值表达式紧挨着开头 $""" 时,C# 解析器可能误判为字符串起始边界的一部分,尤其在 { 前没有空格的情况下。
- 错误写法:
$"""{name} is {age}"""—— 在某些旧版编译器或复杂上下文中可能解析异常 - 安全写法:开头加一个空格,如
$""" {name} is {age} """,或把{换行缩进 - 插值内部仍需正常书写表达式,不支持嵌套原始字符串,比如
$"""Value: { $"""inner""" }"""是非法的 - 注意:插值变量本身若含换行或引号,不会破坏原始字符串结构,因为插值发生在运行时,而非编译期解析
如何在字符串里真正写出 """ 这三个字符
原始字符串的终止符是“连续出现的、数量与开头相等的双引号”,所以要输出字面意义的 """,必须打破这个匹配规则。
- 开头用
""""""(六个引号),结尾也用六个,则中间的"""就是合法内容:string s = """""This contains """ inside"""""; - 规则是:结束引号数 ≥ 开始引号数 + 1,且两边数量严格相等;多出来的引号数决定了能安全嵌入多少个
""" - 不要试图用
\"""或其他转义——原始字符串里根本没有转义机制 - 实际场景常见于 SQL 模板或正则表达式中需要字面匹配三引号的情况,这时提前数好引号层级比事后调试快得多
缩进剪裁不是“自动美化”,而是按行计算的精确裁剪
很多人以为缩进剪裁是“智能去空格”,其实它是机械的:取所有非空内容行的**最小前导空白长度**,然后从每行开头删掉这么多字符(类型和顺序必须一致)。
- 首行(开头
"""后)和末行(结尾"""前)不参与计算 - 空行或只含空白的行被忽略,不影响最小值
- 如果某行缩进少于最小值(比如漏了空格),那这行开头会被裁成负长度——实际结果是该行前面补上对应数量的空格?不,是直接编译失败或行为未定义
- 真实建议:用 IDE 的“显示空白字符”功能打开,确认所有内容行和结尾行的空白符号(空格/Tab)完全一致
最易被忽略的点是:缩进剪裁只作用于“前导空白”,行中或行尾的空格原样保留;而结尾 """ 所在行的空白,哪怕只是多一个空格,整个剪裁逻辑就失效——这时候字符串开头会意外多出大量空格,且毫无警告。











