Секрет фигурных скобок в C#: как правильно экранировать в String.Format

Онлайн-тренажер Python для начинающих

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

Начать курс

Почему фигурные скобки в C# — это головная боль?

Вы когда-нибудь писали код на C#, хотели вывести текст вроде {Имя}: {Значение}, а вместо этого получали FormatException? Если да — вы не одиноки. Вопрос «How to escape curly brace in String.Format» на Stack Overflow собрал десятки тысяч просмотров. И это не случайно: фигурные скобки {} в C# имеют особое значение — они обозначают место для подстановки переменных.

Но что делать, если вам нужно вывести сами скобки как обычные символы? Например, для JSON, шаблонов, генерации кода или просто для красивого форматирования отчёта? Сегодня мы разберём эту тему от и до: от простого экранирования до продвинутых трюков с StringBuilder и интерполяцией строк.

Как экранировать фигурные скобки: базовое правило

Ответ простой и элегантный: удвойте скобку. Если вы хотите вывести одну открывающую скобку {, напишите {{. Для закрывающей } — }}. C# поймёт, что это не плейсхолдер, а обычный символ.

Вот самый простой пример:

string result = string.Format("Значение в фигурных скобках: {{0}}", 42);
Console.WriteLine(result);
// Вывод: Значение в фигурных скобках: {0}

Обратите внимание: {{0}} — это не плейсхолдер, а экранированная пара скобок, внутри которых стоит цифра 0. Если бы мы написали {0}, то получили бы значение переменной (число 42).

Типичная ошибка новичка

Часто начинающие пишут так:

// ОШИБКА!
string bad = string.Format("Привет, {name}!", name);
// FormatException: Input string was not in a correct format.

Почему? Потому что C# ждёт числовой индекс внутри скобок ({0}, {1}), а не имя переменной. Для имён нужно использовать интерполяцию строк (об этом ниже) или явно указывать индексы.

Практические примеры: от простого к сложному

Давайте разберём несколько реальных сценариев, где экранирование скобок необходимо.

1. Вывод JSON или XML в отладочных целях

Представьте, вы пишете логгер и хотите вывести JSON-строку с подстановкой значения:

int userId = 101;
string json = string.Format("{{\"userId\": {0}, \"name\": \"Alice\"}}", userId);
Console.WriteLine(json);
// Вывод: {"userId": 101, "name": "Alice"}

Здесь {{ и }} создают внешние фигурные скобки JSON, а {0} подставляет число.

2. Генерация шаблонов кода

Допустим, вы пишете кодогенератор на C#. Нужно создать строку с шаблоном для другого языка (например, Python или JavaScript):

string template = string.Format("def {0}():\n    return {{0}}", "calculate");
Console.WriteLine(template);
// Вывод:
// def calculate():
//     return {0}

Обратите внимание: {{0}} в строке вывода — это уже не плейсхолдер C#, а часть генерируемого кода (например, для Python).

3. Форматирование с несколькими плейсхолдерами и скобками

Когда нужно смешать подстановки и экранирование, главное — не запутаться в индексах:

string name = "Bob";
int age = 30;
string message = string.Format("Пользователь {{ {0} }} (возраст: {1})", name, age);
Console.WriteLine(message);
// Вывод: Пользователь { Bob } (возраст: 30)

Здесь {{ даёт {, }} даёт }, а {0} и {1} подставляют значения.

Альтернативы String.Format: интерполяция строк и StringBuilder

Хотя string.Format — классика, в современном C# есть более удобные способы. Давайте сравним.

Интерполяция строк (C# 6+)

Интерполяция — это магия $ перед строкой. Она читается лучше, но экранирование скобок остаётся таким же:

int value = 100;
string result = $"Значение в скобках: {{{value}}}";
Console.WriteLine(result);
// Вывод: Значение в скобках: {100}

Как это работает? $"..." включает режим интерполяции. Внутри {} пишутся выражения. Если нужно вывести саму скобку — удваиваем её. В примере выше: {{ -> {, {value} -> 100, }} -> }.

Совет: интерполяция почти всегда предпочтительнее string.Format — она быстрее, безопаснее по типам и легче читается.

StringBuilder: когда нужна производительность

Если вы генерируете огромные строки (например, JSON для API), используйте StringBuilder. Экранирование скобок в нём делается так же — удвоением:

var sb = new StringBuilder();
sb.Append("{{\"key\": \"");
sb.Append("value");
sb.Append("\"}}");
Console.WriteLine(sb.ToString());
// Вывод: {"key": "value"}

Обратите внимание: внутри Append экранирование работает точно так же, как в обычной строке.

Частые ошибки и как их избежать

Даже опытные разработчики иногда спотыкаются на скобках. Вот топ-3 граблей:

  • Забыли удвоить скобку — получите FormatException.
  • Перепутали количество скобок — например, написали {{{0}}} (три скобки). Это даст {42}? Нет! Это даст {42} только если третья скобка непарная. Лучше проверять визуально.
  • Использовали имена вместо индексов в string.Format. Помните: {name} — это ошибка, нужно {0} или интерполяция.

Быстрый чек-лист для проверки:

  • Сколько открывающих скобок { — столько же закрывающих }.
  • Каждая пара {{ или }} даёт одну скобку на выходе.
  • Одиночная скобка {0} — это плейсхолдер.

Продвинутый трюк: экра

Блоги

Рекомендаций по книгам