Как правильно использовать 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 каждый раз, но делает это за счет простоты использования.