Многострочные строковые литералы в C#: как объявить строку с переносами?
Всем привет! Я начинающий C# разработчик, перешел с Python, и столкнулся с проблемой, которая кажется мне очень неудобной.
В Python я мог легко создавать многострочные строки с помощью тройных кавычек:
text = """Это многострочная строка.
Она может содержать переносы строк.
И это очень удобно."""
Но в C# я не могу найти прямого аналога. Когда я пытаюсь записать длинный SQL-запрос, JSON или просто текст с переносами, я получаю ошибки компиляции или мне приходится использовать костыли.
Вот пример того, что я хочу сделать:
string query = "SELECT *
FROM Users
WHERE Age > 18";
Очевидно, что так писать нельзя — компилятор ругается. Я знаю про конкатенацию строк и про @-строки (verbatim string), но они не решают проблему полностью.
Подскажите, есть ли в C# 7, 8, 9 или более новых версиях нормальная поддержка многострочных строковых литералов? Как правильно объявлять длинные строки с переносами в C#, чтобы код оставался читаемым?
Буду благодарен за примеры с объяснением.
<<Решение: Многострочные строки в C# 11 и новее (сырые строковые литералы)
Начиная с C# 11 (.NET 7), в языке появилась полноценная поддержка многострочных строковых литералов — сырые строковые литералы (raw string literals). Это именно то, что вы ищете, и они очень похожи на тройные кавычки из Python.
Синтаксис простой: используйте три двойные кавычки """ для открытия и закрытия строки. При этом:
- Строка может содержать любые символы, включая переносы строк, кавычки и обратную косую черту.
- Отступы (пробелы и табуляции) автоматически выравниваются по самому левому символу содержимого.
- Не нужно экранировать кавычки внутри строки (если их меньше двух подряд).
Пример 1: Простой SQL-запрос
string query = """
SELECT *
FROM Users
WHERE Age > 18
""";
Console.WriteLine(query);
// Вывод:
// SELECT *
// FROM Users
// WHERE Age > 18
Пример 2: JSON с отступами
string json = """
{
"name": "John",
"age": 30,
"city": "New York"
}
""";
Console.WriteLine(json);
Важно про отступы: Закрывающие кавычки """ определяют уровень отступа. Если вы поставите их на том же уровне, что и содержимое, отступов не будет. Если сдвинете влево — отступы обрежутся. Рекомендуется ставить закрывающие кавычки на том же уровне, что и содержимое.
Что было до C# 11? (Если вы используете старую версию)
Если у вас C# 10 или старше, есть два основных подхода:
Вариант A: Verbatim string с конкатенацией
string query = @"SELECT *
FROM Users
WHERE Age > 18";
Минус: переносы строк в коде становятся частью строки. Если нужно убрать отступы, придётся писать всё с начала строки (без отступов), что ухудшает читаемость.
Вариант B: Интерполированные строки (с $)
string query = $@"SELECT *
FROM Users
WHERE Age > 18";
Работает, но то же ограничение по отступам.
Вариант C: StringBuilder для очень больших строк
var sb = new StringBuilder();
sb.AppendLine("SELECT *");
sb.AppendLine("FROM Users");
sb.AppendLine("WHERE Age > 18");
string query = sb.ToString();
Рекомендация
Если у вас .NET 7 или новее — используйте сырые строковые литералы ("""..."""). Это самый чистый и современный способ. Если проект на старой версии — используйте @"" с конкатенацией, но будьте готовы к проблемам с форматированием.
Альтернативный подход: Использование StringBuilder с файлами ресурсов
Если вы часто работаете с большими многострочными строками (например, SQL-запросами, HTML-шаблонами или JSON-конфигами), я рекомендую выносить их в отдельные файлы или использовать ресурсы (.resx). Это сделает код чище и упростит поддержку.
Пример с файлом ресурсов:
- Создайте файл ресурсов (например,
Queries.resx) в проекте. - Добавьте в него строку с именем
GetUsersQueryи значением вашего SQL-запроса. - Используйте его в коде:
string query = Properties.Resources.GetUsersQuery;
// Или, если используете глобальные using:
string query = Queries.GetUsersQuery;
Преимущества этого подхода:
- Строки не засоряют код.
- Легко менять запросы без перекомпиляции всего проекта (если использовать внешние файлы).
- Поддержка локализации.
Альтернатива для JSON: Храните JSON в отдельных .json файлах и загружайте их через File.ReadAllText() или встроенные методы сериализации. Это особенно удобно для тестовых данных.
Таким образом, если вам не нужны динамические строки с интерполяцией, выносите многострочные данные из кода — это улучшит читаемость и поддерживаемость проекта.