Как работает StringBuilder в C#?

Ответ

StringBuilder — это класс в .NET, оптимизированный для эффективной работы с изменяемыми строками. В отличие от обычных строк (string), которые являются иммутабельными (каждое изменение создает новый объект в памяти), StringBuilder использует внутренний буфер символов, который можно изменять без постоянных переаллокаций.

Ключевые принципы работы:

  1. Буфер в памяти: StringBuilder хранит символы в массиве (char[]). При создании можно задать начальную емкость (capacity).
  2. Динамическое расширение: Если при добавлении данных (Append, Insert) места в буфере не хватает, он автоматически увеличивается (обычно удваивается). Это дорогая операция, поэтому при известном ожидаемом размере строки лучше задать начальную емкость в конструкторе.
  3. Изменение на месте: Методы Append(), Insert(), Remove(), Replace() и Clear() работают с существующим буфером.
  4. Финальное преобразование: Метод ToString() создает новую неизменяемую строку (string) на основе текущего содержимого буфера.

Пример использования:

// Создание с начальной емкостью (оптимизация для больших строк)
var sb = new StringBuilder("Hello", 50);

// Эффективная конкатенация в цикле
for (int i = 0; i < 100; i++)
{
    sb.Append(i); // Не создает 100 новых строковых объектов
}

// Другие операции
sb.Insert(5, " C#"); // "Hello C#0123..."
sb.Replace("Hello", "Hi"); // "Hi C#0123..."

// Получение результата
string finalString = sb.ToString();

Когда использовать StringBuilder:

  • Конкатенация строк в циклах (особенно с большим числом итераций).
  • Построение больших строк из множества фрагментов (например, генерация HTML, SQL-запросов, JSON).

Когда НЕ нужно использовать: Для простой конкатенации нескольких строк (string.Concat или интерполяция $"{} {}"`) обычно достаточно и эффективнее.

Ответ 18+ 🔞

Слушай, вот есть у тебя обычная строка в C# — string. Так вот, эта сука намертво замороженная, как будто её в лёд вогнали. Хочешь букву поменять? Хуй там! Хочешь что-то добавить? Пиздец! Каждое изменение — это новый объект в памяти, старая строка на свалку, новая создаётся. Если это в цикле на тысячу итераций, то ты, по сути, тысячу раз мусор генерируешь и память трамбуешь. Компьютер начинает ебаться как проклятый.

А теперь представь себе StringBuilder. Это как будто у тебя есть умная динамическая ёмкость, ведро, блядь. Ты туда символы складываешь, а оно само расширяется, когда места мало. Всё происходит в одном месте, без этих ебучьих постоянных переездов данных из старой квартиры в новую.

Как эта штука устроена, если по-простому:

  1. Внутри — массив символов. Просто char[], и всё. Создаёшь StringBuilder — можешь даже сказать: «Слушай, я планирую где-то 500 символов накидать, сделай мне буфер с запасом». Это чтобы сразу не ебаться с расширением.
  2. Растёт по-умному. Кидаешь ты в него данные методом Append, а места уже нет. Он не паникует. Он берёт и увеличивает свой внутренний массив, обычно в два раза. Да, это операция не из лёгких, поэтому если знаешь примерный размер итоговой строки — лучше сразу намекни в конструкторе, чтоб не дергался по мелочам.
  3. Меняй что хочешь. Append (добавить в конец), Insert (воткнуть в середину), Remove (вырезать кусок), Replace (заменить одно на другое) — всё это происходит прямо в том же самом буфере, на месте. Никакой лишней возни.
  4. А результат — обычная строка. Когда всё готово, вызываешь ToString(), и он тебе из накопленного в буфере добра собирает красивую, нормальную, неизменяемую строку string. Всё, дело сделано.

Вот смотри, как это выглядит в коде:

// Делаем StringBuilder и сразу говорим: "Привет, и будь готов, я до 50 символов напихаю"
var sb = new StringBuilder("Hello", 50);

// Допустим, надо строку из чисел собрать. С обычным string в цикле — пиздец и ужас.
// А тут — красота, всё в одном буфере.
for (int i = 0; i < 100; i++)
{
    sb.Append(i); // Ни одной новой строки не создалось, просто цифры в массив дописались
}

// Ой, забыл в середину вставить "C#". Без проблем!
sb.Insert(5, " C#");
// Захотел "Hello" на "Hi" поменять — тоже ок.
sb.Replace("Hello", "Hi");

// Всё, строим финальную строку.
string finalString = sb.ToString(); // Вот теперь получился полноценный string

Так когда же эту бандуру использовать?

  • Когда в цикле строки собираешь. Особенно если итераций дохуя. Это главный кейс, ради которого всё и затевалось.
  • Когда строишь что-то огромное и сложное. Ну там HTML-страницу, SQL-запрос на три экрана, JSON-ответ API — короче, любую хрень, которая собирается из кучи мелких кусочков.

А когда НЕ надо?

Да когда операция разовая и простая! Сконкатенировать две-три строки или использовать интерполяцию $"Привет, {name}" — для этого StringBuilder заводить, это всё равно что из пушки по воробьям палить. Обычный string или string.Concat() справятся быстрее и проще. Не усложняй там, где не надо.