Почему советуют StringBuilder вместо склейки строк через + в цикле?
Собираю большую строку в цикле, складывая через +=:
string result = "";
for (int i = 0; i < 100000; i++)
result += i + ",";
Работает, но дико тормозит. Подсказали использовать StringBuilder. Почему обычная конкатенация такая медленная и как правильно применить StringBuilder?
2 ответа
Причина в том, что строки в C# неизменяемы (immutable). Каждый раз, когда вы делаете result += ..., создаётся совершенно новая строка, а старая копируется целиком. В цикле на 100000 итераций это сотни тысяч копирований и мусора для сборщика — отсюда тормоза (по сути O(n²)).
StringBuilder хранит изменяемый внутренний буфер и дописывает в него без пересоздания:
using System.Text;
var sb = new StringBuilder();
for (int i = 0; i < 100000; i++)
sb.Append(i).Append(',');
string result = sb.ToString(); // финальную строку получаем один раз
Полезные методы:
sb.Append("текст");
sb.AppendLine("строка с переносом");
sb.AppendFormat("{0} = {1}", "x", 42);
sb.Insert(0, "в начало");
sb.Clear(); // очистить и переиспользовать
Когда использовать: много склеек в цикле — StringBuilder. Если же это пара строк (a + b + c), обычный + нормален и читается лучше — компилятор и так оптимизирует его в один вызов.
Если нужно просто объединить готовую коллекцию через разделитель, то не нужен ни +, ни даже StringBuilder вручную — есть string.Join:
var numbers = Enumerable.Range(0, 100000);
string result = string.Join(",", numbers);
Он внутри сам использует эффективную сборку. StringBuilder берите, когда логика построения строки сложнее простого соединения элементов.