C# 11 原始字符串字面量详解:多行文本、引号和插值终于好写了

Mia
Mia
发布时间:2026-08-24| 141人浏览过
原创

前言

C# 里最让人头疼的字符串,往往不是内容本身,而是转义、换行和缩进把代码搅得难读难改。C# 11 引入的原始字符串字面量,正好把这些问题拆开处理。本文从语法、边界规则、插值写法到典型场景逐项说明,帮你判断它适不适合替换现有的普通字符串和逐字字符串。

C# 在处理 JSON、XML、SQL、正则和代码模板时,字符串可读性一直是个老问题:要么转义太多,要么换行和缩进难以维护。C# 11 提供的原始字符串字面量,正是为这类场景准备的。下面就按语法、边界规则、插值方式和典型应用逐段拆开,看它到底解决了什么问题,以及在实际项目里该怎么用。

什么是原始字符串字面量

从 C# 11 开始,原始字符串字面量(Raw String Literals)成为正式特性。它的核心目标很直接:让字符串内容尽可能按“原样”写进代码里,减少对特殊字符的转义处理。

这类字符串以至少三个双引号 """ 作为开始和结束分隔符,可以跨越多行,也可以直接包含引号、反斜杠等常见“麻烦字符”。对于经常要写配置片段、文档文本、查询语句或模板内容的开发者来说,它比传统写法更接近最终输出结果。

它解决了哪些老问题

  • 不用频繁写转义符,代码阅读压力更小

  • 天然支持多行文本,不必再靠字符串拼接维持格式

  • 能保留文本结构,尤其适合结构化内容

  • 可与插值语法结合,适合动态模板生成

和传统字符串相比差别在哪

特性常规字符串逐字字符串(@)原始字符串字面量
转义需求需要转义特殊字符不需要转义,但对双引号仍需转义完全不需要转义
多行支持需使用n等支持原生支持
缩进保留不保留保留所有缩进智能缩进处理
引号处理\"\"\"直接使用
JSON/XML可读性差可读性中等完美呈现

如果字符串内容本身就接近配置文件、标记语言或查询脚本,原始字符串通常会比普通字符串和 @ 逐字字符串更自然。

展示 C# 原始字符串在缩进处理和引号分隔符上的核心规则,帮助读者快速判断多行文本会怎样输出。
原始字符串的边界规则图解用图解方式梳理原始字符串最容易混淆的两条规则:公共缩进裁剪。

基本语法怎么写

原始字符串的基本形式并不复杂,关键点是分隔符和换行位置。最少使用三个双引号,既可以写成单行,也可以写成多行。

// 基本原始字符串
string basic = """这是一个原始字符串,不需要转义 "引号" 和 反斜杠""";

// 多行原始字符串
string multiLine = """
    这是一个
    多行原始字符串
    可以包含 "引号" 和 反斜杠
    """;

// 包含大括号的原始字符串
string withBraces = """
    { "name": "John", "age": 30 }
    """;

可以把它理解成“所见即所得”的字符串写法。尤其在多行场景下,文本长什么样,输出通常就接近什么样,维护起来会轻松很多。

为什么这种写法更适合多行内容

传统字符串在多行文本里往往要依赖换行符和拼接:

归纳 C# 原始字符串最典型的四类落地场景,帮助读者快速判断项目中的使用优先级。
四类高收益使用场景当字符串本身带结构、格式或嵌套符号时,原始字符串的收益最明显。
// 传统多行字符串(需要转义和连接)
string oldMultiLine = "第一行n" +
                     "第二行n" +
                     "第三行";

// 原始多行字符串(更简洁)
string newMultiLine = """
    第一行
    第二行
    第三行
    """;

// JSON 示例
string json = """
    {
        "name": "John Doe",
        "age": 30,
        "email": "john@example.com"
    }
    """;

从可读性看,这种差异非常明显。特别是当文本内部已经包含大量双引号时,原始字符串的优势会进一步放大。

真正容易踩坑的两条规则:缩进与引号数量

原始字符串看上去简单,但在实际使用中,最需要理解的不是“能不能写”,而是“编译器如何判断边界”。这里主要有两件事:缩进处理,以及分隔符双引号数量规则。

缩进是如何处理的

多行原始字符串会根据结束分隔符的位置,自动决定要去掉多少公共缩进。这样既能让代码在方法体内保持整齐,又不会把无意义的左侧空白一并带进结果。

string GetFormattedMessage()
{
    return """
        Hello,
            This is an indented message.
        It preserves the formatting exactly as written.
        """;
}

// 输出结果:
// Hello,
//     This is an indented message.
// It preserves the formatting exactly as written.

这意味着你可以在代码里保持缩进层次,同时让真正的文本格式仍然可控。对于消息模板、提示词、Markdown 片段等内容,这个行为很实用。

最小缩进的判断方式

如果把结束引号放在某个缩进层级,编译器会按这个层级去掉每一行对应的公共前导空白:

string minimalIndent = """
    First line
    Second line
    Third line
    """; // 结束引号的缩进决定了最小缩进

// 等效于:
// "First linenSecond linenThird line"

因此,多行原始字符串是否“看起来对齐”,直接影响最终内容。团队里如果同时写模板和配置,最好统一缩进习惯。

内容里有很多引号时怎么办

如果字符串内容本身包含连续的双引号,那么分隔符就必须比内容中的最长连续双引号更多。原文里的原则可以直接记成一条公式:N > M。

  • 分隔符的双引号数量 N 必须大于内容中连续双引号的最大数量 M

  • 最小分隔符数量为 3

  • 判断规则就是 N > M

// 内容包含三个双引号 → 使用四个作为分隔符
string tripleQuotes = """" 这里可以包含 """ 三个引号 """";

// 内容包含四个双引号 → 使用五个作为分隔符
string fourQuotes = """"" 这里可以包含 """" 四个引号 """"";

这条规则看起来有点绕,但记忆成本其实不高:内容里连续引号越多,包裹它的分隔符就再多一个。

和字符串插值一起用时,重点看 $ 和大括号

原始字符串并不排斥插值,反而非常适合生成动态 JSON、代码模板和配置片段。这里的关键在于:$ 的数量决定了插值表达式的边界。

展示 C# 原始字符串与插值语法结合时,$ 数量和大括号边界之间的对应关系。
$ 与插值边界对应关系原始字符串支持插值,但要先看懂 $ 的层级规则:$ 越多,可直接保留在文本里的大括号就越多。
  • 一个 $,表达式写成 { }

  • 两个 $$,表达式写成 {{ }}

  • 继续增加时,规则以此类推

string name = "John";
int age = 30;

// 基本插值
string interpolated = $$"""
    {
        "name": "{{name}}",
        "age": {{age}}
    }
    """;

// 复杂插值(使用多个$符号)
string complex = $$$"""
    {
        "name": "{{{name}}}",  // 注意:这里需要三个大括号
        "age": {{age}}
    }
    """;

这套设计的意义在于,字符串本体里如果原本就有很多大括号,例如 JSON、模板语法、代码生成脚本,编译器仍然能区分哪些是文本,哪些是要计算的表达式。

为什么它特别适合模板输出

传统插值字符串一旦叠加 JSON 或代码模板,往往很快会出现转义、大括号嵌套、换行混乱三件套。原始字符串把这些问题拆开了:

  • 引号保留原样

  • 换行保留原样

  • 通过 $ 数量控制插值边界

这也是它在模板生成类代码中最有价值的地方。

哪些场景最适合用原始字符串

如果只是存一个很短的提示文本,原始字符串未必有必要。但只要文本带结构、带格式、带嵌套符号,它就会明显更顺手。下面几类是最典型的使用场景。

JSON 和 XML

// JSON 配置
string configJson = """
    {
        "appSettings": {
            "timeout": 30,
            "retryCount": 3,
            "apiUrl": "https://api.example.com"
        },
        "logging": {
            "level": "Information",
            "filePath": "logs/app.log"
        }
    }
    """;

// XML 文档
string xmlDocument = """
    
    
        
            Gambardella, Matthew
            XML Developer's Guide
            Computer
            44.95
            2000-10-01
            An in-depth look at creating applications with XML.
        
    
    """;

这类内容本身就强调层级和格式。用原始字符串后,代码里的文本结构和实际输出高度一致,阅读成本会低很多。

正则表达式

// 复杂的正则表达式(无需转义反斜杠)
string emailPattern = """^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$""";
string phonePattern = """^(+d{1,3}s?)?((d{1,4})s?)?d{1,4}[s.-]?d{1,4}[s.-]?d{1,9}$""";

// 使用正则表达式
bool isValidEmail = Regex.IsMatch("test@example.com", emailPattern);

正则本来就充满反斜杠和边界符,一旦还要再为 C# 字符串做二次转义,可读性会迅速下降。原始字符串在这里的价值非常直接:让模式本身更接近你真正想表达的内容。

SQL 查询

string sqlQuery = """
    SELECT 
        u.Id,
        u.Name,
        u.Email,
        COUNT(o.Id) AS OrderCount
    FROM Users u
    LEFT JOIN Orders o ON u.Id = o.UserId
    WHERE u.IsActive = 1
    GROUP BY u.Id, u.Name, u.Email
    HA VING COUNT(o.Id) > 0
    ORDER BY OrderCount DESC
    """;

多行 SQL 是另一个明显收益点。查询结构、字段列表、连接条件和排序语句都能按数据库常见格式排版,不必在字符串拼接中来回找错。

代码生成与模板拼装

string GenerateCSharpClass(string className, IEnumerable<string> properties)
{
    return $$"""
        public class {{className}}
        {
            {{string.Join("n    ", properties.Select(p => $"public string {p} {{ get; set; }}"))}}
            
            public {{className}}()
            {
            }
            
            public override string ToString()
            {
                return $"{{
                    {{string.Join(", ", properties.Select(p => $"{p}={{{p}}}"))}}
                }}";
            }
        }
        """;
}

// 使用示例
string classCode = GenerateCSharpClass("Person", new[] { "FirstName", "LastName", "Age" });

这类场景最能体现“原始字符串 + 插值”的组合价值。模板结构保持完整,变量替换也足够直观,后续扩展字段、方法或注释时不容易把字符串本身改乱。

怎么判断项目里该不该用

原始字符串字面量不是要替代所有字符串写法,而是更适合那些“文本本身就值得被看清”的内容。它最突出的优势包括:

  • 消除大量转义需求

  • 原生支持多行内容

  • 能配合缩进规则保持代码整洁

  • 支持与插值结合生成动态文本

  • 编译时处理,无额外运行时性能负担

优先考虑使用的情况

  • JSON/XML/HTML 等结构化文本

  • 复杂正则表达式

  • 多行 SQL 查询

  • 代码生成和模板输出

  • 需要保留格式的文档字符串

如果字符串很短、没有特殊字符,也不涉及多行或模板,普通字符串依然足够简单。但只要你开始频繁写 \、\"、+ 拼接,或者为了排版牺牲可读性,就可以优先考虑改用 C# 11 的原始字符串字面量。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。