Как правильно использовать StringBuilder
Я немного запутался в использовании класса StringBuilder
, сначала:
Операция конкатенации объектов A string
всегда создает новый объект из существующих string
и новых данных. Объект StringBuilder
поддерживает буфер для размещения конкатенации новых данных. Новые данные добавляются в конец буфера, если комната доступна; в противном случае выделяется новый более крупный буфер, данные из исходного буфера копируются в новый буфер, затем новые данные добавляются в новый буфер.
Но где создать экземпляр StringBuilder
, чтобы избежать создания нового из string
? Это звучит как торговля "один на один".
static void Main(string[] args)
{
String foo = "123";
using (StringBuilder sb = new StringBuilder(foo)) // also sb isn't disposable, so there will be error
{
sb.Append("456");
foo = sb.ToString();
}
Console.WriteLine(foo);
Console.ReadKey();
}
Почему я не должен просто использовать
+=
Изменить: Хорошо, теперь я знаю, как повторно использовать один экземпляр StringBuilder
(до сих пор не знаю, соответствует ли это стандартам кода), но это не стоит использовать с только один string
, не так ли?
Ответы
Ответ 1
Изменение immutable таких структур, как string
необходимо сделать, скопировав структуру и тем самым потребляя больше памяти и замедляя время выполнения приложения (также увеличивая время GC
и т.д.).
StringBuilder
приходит к решению этой проблемы, используя тот же изменяемый объект для манипуляций.
Однако:
при конкатенации string
во время компиляции следующим образом:
string myString = "123";
myString += "234";
myString += "345";
он действительно скомпилирует что-то вроде этого:
string myString = string.Concat("123", "234", "345");
эта функция работает быстрее, чем работает с StringBuilder
для числа string
, входящего в функцию.
поэтому для конкатенаций string
для компиляции-времени вы предпочитаете string.Concat()
.
как для неизвестного числа string
, как в следующем случае:
string myString = "123";
if (Console.ReadLine() == "a")
{
myString += "234";
}
myString += "345";
Теперь компилятор не может использовать функцию string.Concat()
, однако StringBuilder
оказывается более эффективным во времени и потреблении памяти только тогда, когда конкатенация выполняется с 6-7 или более strings
.
Плохое использование практики:
StringBuilder myString = new StringBuilder("123");
myString.Append("234");
myString.Append("345");
Использование тонкой практики (обратите внимание, что используется if
):
StringBuilder myString = new StringBuilder("123");
if (Console.ReadLine() == "a")
{
myString.Append("234");
}
myString.Append("345");
Лучшее использование практики (обратите внимание, что используется цикл while
):
StringBuilder myString = new StringBuilder("123");
while (Console.ReadLine() == "a")
{
myString.Append("234"); //Average loop times 4~ or more
}
myString.Append("345");
Ответ 2
A string
- непреложный класс. Вы не можете изменить его, только создайте новый strings
.
Поэтому, когда вы пишете result += a;
, в этой точке у вас есть три отдельных strings
: a
, старое значение result
и новое значение. Конечно, это абсолютно нормально, если вы только конкатенируете ограниченное число strings
. Если вы сделаете это в цикле for
, итерации по большой коллекции, это может стать проблемой.
Класс StringBuilder
обеспечивает улучшенную производительность в этих случаях. Вместо создания нового strings
для хранения результата конкатенации он использует один и тот же объект. Поэтому, если вы используете stringBuilder.Append(a);
, у вас никогда не будет эквивалента "старого значения result
".
Эффективность этой памяти, конечно, идет с ценой. Когда только конкатенирование небольшого числа strings
a StringBuilder
часто менее эффективно в отношении скорости, так как оно имеет больше накладных расходов по сравнению с неизменяемым классом string
.
Следует иметь в виду, что если вам нужны промежуточные строки, то StringBuilder
может стать менее эффективным, так как при вызове .ToString()
на нем создается новая копия string
.
Ответ 3
Причина в том, что strings
неизменяемы. При конкатенировании string
вы создаете новый string
. Итак, когда вам нужно объединить многие strings
, вы создаете много objects
. Это не так дорого в плане памяти, поскольку каждый string
используется один раз. Но это дает дополнительную работу для GC
.
StringBuilder
однако использует один и тот же object
каждый раз, но делает это за счет простоты использования.