Когда использовать StringBuilder, а когда string? Как работает StringBuilder?csharp-84

Когда использовать string?

  1. Для коротких строк (до 10-15 конкатенаций)
  2. Когда строка не изменяется после создания
  3. Для константных значений и литералов
  4. В однопоточных сценариях без частых модификаций
string greeting = "Hello";
string name = "John";
string message = greeting + " " + name + "!"; // Простая конкатенация

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

  1. Множественные модификации строки (более 10-15 операций)
  2. Большие строки или сложные преобразования
  3. Циклы с конкатенацией строк
  4. Высокопроизводительные сценарии
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.Append(i).Append(", ");
}
string result = sb.ToString();

Как работает StringBuilder?

Внутренняя структура:

  1. Буфер символов (char array):

    • Начинается с емкости по умолчанию (16 символов в .NET Core)
    • Динамически расширяется при необходимости
  2. Механизм роста:

    • При заполнении буфера создается новый массив (обычно в 2 раза больше)
    • Существующие символы копируются в новый массив
    • Старый массив становится доступным для GC

Ключевые особенности:

  1. Изменяемость:

    • В отличие от string, StringBuilder мутабелен
    • Операции модификации работают с тем же объектом
  2. Методы для эффективной работы:

    • Append(), Insert(), Remove(), Replace()
    • Поддержка цепочки вызовов (Fluent API)
  3. Управление емкостью:

    • Можно задать начальную емкость
    • Можно уменьшить емкость до фактического размера
// Оптимизация с предустановленной емкостью
var sb = new StringBuilder(initialCapacity: 1024);

Производительность

Сравнение операций :

Операция string (мс) StringBuilder (мс)
Конкатенация в цикле 15-20 0.1-0.3
Многократный Append N/A 0.1-0.5

Память:

  • string: создает новый объект при каждой операции
  • StringBuilder: минимизирует аллокации за счет буфера

Лучшие практики

  1. Задавайте начальную емкость, если знаете примерный размер:

    new StringBuilder(estimatedLength);
    
  2. Используйте Clear() для повторного использования:

    sb.Clear().Append("New content");
    
  3. Избегайте избыточных ToString():

    // Плохо:
    sb.Append(someStringBuilder.ToString());
    
    // Хорошо:
    sb.Append(someStringBuilder);
    
  4. Для простых сценариев используйте интерполяцию строк:

    string message = $"{greeting} {name}!"; // Компилятор оптимизирует
    

Как работает под капотом?

  1. Append:

    • Проверяет достаточно ли места в буфере
    • При необходимости увеличивает буфер
    • Копирует новые символы в буфер
  2. ToString:

    • Создает новый string из текущего буфера
    • Если емкость равна длине, использует текущий буфер

Резюмируем:

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