Необработанные строковые литералы

Подсказка

Эта статья является частью раздела "Основы" для разработчиков , которые уже знают хотя бы один язык программирования и учат C#. Если вы не знакомы с программированием, сначала начните с учебных пособий по началу работы. Полный грамматический код см. в справочнике по языку.

Вы пришли из другого языка? Необработанные строковые литералы в C# выполняют ту же функцию, что и строки r"..." в Python и Rust, текстовые блоки в Java ("""..."""), а также строки шаблонов в обратных кавычках в JavaScript, TypeScript и Go. Синтаксис C# ближе всего к текстовым блокам Java с дополнительными правилами для разделителей переменной длины и интерполяции.

Необработанный строковый литерал разделен тремя или более двойными кавычками. Внутри ограничителей каждый символ воспринимается буквально. Кавычки и обратные слеши не нужно экранировать, а символы новой строки сохраняются в том виде, в котором записаны. Используйте необработанные строки для любой строки, содержащей кавычки, обратные очки или несколько строк: JSON, XML, SQL, регулярные выражения, пути к файлам и примеры кода.

Предупреждение

Необработанный строковый литерал упрощает чтение SQL, но это не делает SQL более безопасным. Никогда не сцепляйте или интерполяйте предоставленные пользователем значения в команду SQL. Такая практика делает ваше приложение уязвимым для SQL-инъекций. Используйте параметризованные команды вместо этого: DbCommand.CreateParameter с DbParameterCollection.Add или вспомогательными средствами более высокого уровня в Entity Framework Core и Dapper. Эта же осторожность применяется к другим форматам, подверженным внедрению, таким как команды оболочки, фильтры LDAP и HTML.

Литерал, содержащий кавычки и обратные косые черты

Обычный литерал нуждается в обходе " и \. Дословный литерал по-прежнему должен "" включать цитату. Сырой литерал не нуждается ни в том, ни в другом:

// Same JSON value, three ways:
string regular  = "{ \"name\": \"Ada\", \"path\": \"C:\\\\src\" }";
string verbatim = @"{ ""name"": ""Ada"", ""path"": ""C:\\src"" }";
string raw      = """{ "name": "Ada", "path": "C:\\src" }""";

Console.WriteLine(regular  == raw);   // True
Console.WriteLine(verbatim == raw);   // True

Каждая форма создает ту же строку, но необработанная версия считывается точно так же, как в формате JSON, который он представляет.

Однострочные необработанные строки

Открывающий и закрывающий разделители состоят как минимум из трёх двойных кавычек, при этом закрывающий разделитель должен содержать такое же количество кавычек, что и открывающий разделитель. Содержимое находится между ними на одной строке. Кавычки и обратные косые скобки внутри содержимого являются литеральными:

// A raw string literal starts and ends with at least three quotes.
// Inside, " and \ are literal — no escaping required.
string message = """She said "hi" and left.""";
string regex   = """\d{3}-\d{4}""";

Console.WriteLine(message);   // She said "hi" and left.
Console.WriteLine(regex);     // \d{3}-\d{4}

Однострочная сырая строка не может быть пустой между ограничителями. Он может заканчиваться двойной кавычкой, но не может начинаться с неё. Компилятор рассматривает двойную кавычку в начале как дополнительный открывающий символ-разделитель. Если содержимое должно начинаться с кавычки, вместо этого используйте многострочный необработанный строковый литерал, который размещает содержимое на отдельной строке, где начальная кавычка трактуется однозначно.

Многостроковые необработанные строки

Для многостроного содержимого открывающий разделитель заканчивает строку, а закрывающий разделитель запускается самостоятельно. Как и в случае с необработанными строками, разделитель имеет три или более двойных кавычки, а закрывающий разделитель должен использовать то же количество кавычек, что и открывающий. Обычно используют три кавычки, но можно использовать четыре, пять или больше, если само содержимое содержит последовательность символов """. Все между двумя разделителями — это значение строки, точно как написано:

// The opening """ and closing """ each sit on their own line.
// The content between them is the value, exactly as written.
string sql = """
    SELECT id, name
    FROM customers
    WHERE active = 1
    """;

Console.WriteLine(sql);

Новая строка сразу после открытия """ и новой линии непосредственно перед закрытием """ не является частью значения. Они — пробелы разделителей. Аналогичным образом компилятор удаляет все пробелы слева от закрывающего тега """ в каждой строке содержимого, так что вы можете добавить литералу отступ, чтобы он соответствовал окружающему блоку кода, и при этом этот отступ не попадёт в строку. В следующем разделе подробно рассматривается это правило.

Если само содержимое содержит последовательность """, используйте в качестве разделителей четыре или более кавычек. Число разделителей должно просто превышать самую длинную последовательность кавычек в содержимом текста. См. полные правила в разделе Необработанные строковые литералы (справочник по языку).

Отступ: закрывающий разделитель задает поле

Столбец, в котором расположен закрывающий тег """, определяет левый отступ. Компилятор удаляет пробелы до этого столбца из каждой строки содержимого. Это правило позволяет отступить литерал в соответствии с окружающим кодом, не загрязняя значение:

// The column of the closing """ sets a left margin.
// Whitespace up to that column is stripped from every content line.
string xml = """
        <order id="42">
            <item>book</item>
        </order>
        """;

// First content line begins at column 0 of the value:
Console.WriteLine(xml);
// <order id="42">
//     <item>book</item>

Если строка содержимого имеет меньше ведущих символов пробелов, чем столбец закрывающего разделителя, компилятор сообщает об ошибке. Все строки содержимого должны иметь отступ не меньше, чем у закрывающего тега """.

Необработанные интерполированные строки

$ Добавьте префикс в необработанную строку, чтобы включить интерполяцию. Выражения в отверстиях вычисляются, и их результаты вставляются в {} значение:

// A single $ before """ enables interpolation: single { and } mark a hole.
// Inside a single-$ raw string, literal braces aren't allowed — use $$ when
// the content also contains literal { or }.
string name = "Ada";
int    score = 95;

string report = $"""
    Player:  {name}
    Score:   {score}
    Updated: {DateTime.UtcNow:yyyy-MM-dd}
    """;

Console.WriteLine(report);

Если интерполированное содержимое также должно содержать литеральные символы { или }, см. статью Необработанные строковые литералы (справочник по языку).

Когда выбирать, какой литерал

Используйте необработанный строковый литерал всякий раз, когда содержимое содержит кавычки, обратные очки или несколько строк. В результате текст стал короче, его легче читать, вставлять и копировать, и он не содержит ошибок, связанных с escape-последовательностями.

Используйте обычный строковый литерал для коротких однострочных значений без кавычек или обратных косых кавычек, таких как имена, сообщения, заполнители формата.

Используйте дословный строковый литерал (@"...") только при работе с существующим кодом, использующим их. Для нового кода сырые строковые литералы покрывают все случаи использования, которые покрывают дословные строковые литералы, при этом обеспечивая более чистый синтаксис для встроенных кавычек.

См. также