Что такое StringBuilder в C# и когда его использовать?
Что проверяют
Понимаете ли неизменяемость строк в .NET и умеете ли назвать границу, за которой StringBuilder начинает выигрывать. Ответ «он быстрее» без условий считают заученным, потому что на коротких склейках он как раз медленнее.
Как отвечать
string неизменяем: любая операция возвращает новую строку, а старая становится мусором. Склейка в цикле поэтому даёт квадратичный объём копирования и нагружает сборщик мусора. StringBuilder держит изменяемый буфер, дописывает в него на месте и материализует результат один раз, в вызове ToString.
Когда брать:
- сборка строки в цикле или рекурсии, когда число частей заранее неизвестно;
- много операций
Append,Insert,Replaceнад одним и тем же текстом; - известен примерный размер: задать ёмкость в конструкторе, чтобы буфер не рос по ходу.
Когда не брать: фиксированное число кусков. Интерполяция и + в одном выражении компилятор сворачивает в один вызов конкатенации, и это быстрее, чем заводить builder. Для коллекции строк есть string.Join, для действительно горячего кода string.Create и работа со Span<char>.
var sb = new StringBuilder(capacity: 1024);
foreach (var row in rows) sb.Append(row.Id).Append(';');
var text = sb.ToString();Где спотыкаются
Применяют StringBuilder на двух или трёх конкатенациях подряд, потому что «так правильнее». Код становится длиннее и медленнее: выделяется сам builder плюс буфер, а сэкономить нечего.
Зовут ToString внутри цикла, например чтобы залогировать промежуточный результат. Каждый такой вызов копирует весь накопленный буфер, и выигрыш обнуляется ровно тем способом, от которого уходили.
Называют StringBuilder потокобезопасным. Он не потокобезопасен, один общий экземпляр под несколькими потоками даёт перемешанный текст и падения. Рядом живёт вторая ошибка того же корня: думают, что Replace у строки меняет её на месте, тогда как он возвращает новую строку, а исходная не меняется никогда.