StringBuilder

Поскольку объекты System. String являются неизменяемыми, иногда они становятся узким местом для эффективности, например, при сборе строки “на лету”. Для построения составной строки можно воспользоваться операцией +, как показано ниже:

1
2
string space = " ";
string compound = "Голосуйте" + space + "за" + space + "тишину";

Однако такой подход неэффективен, поскольку код для выполнения своей работы создает множество строк. Создание таких промежуточных строк может увеличить нагрузку на память. Хотя эта строка кода несколько искусственна, совсем несложно представить, как пострадает эффективность сложной системы, в которой производится масса манипуляций строками, от интенсивного использования памяти.

Рассмотрим случай реализации пользовательского кодировщика base64, который последовательно добавляет символы в процессе обработки двоичного файла. Библиотека .NET уже предоставляет эту функциональность в классе System. Convert, но давайте пока ее проигнорируем.

Если многократно в цикле использовать операцию + для создания огромной строки base64, производительность очень быстро деградирует по мере увеличения размера исходных данных. В такой ситуации можно прибегнуть к классу System.Text. , который реализует изменяемую строку специально для эффективного построения составных строк.

Детальное описание методов здесь приводиться не будет, поскольку при желании его можно найти в документации MSDN, однако будет раскрыт ряд моментов, о которых обычно умалчивается. Внутри поддерживает массив символов, которым управляет динамически. Основными рабочими методами этого класса являются Append, Insert и AppendFormat.

По описанию этих методов в MSDN видно, что они имеют богатый набор перегрузок для поддержки добавления и вставки строк многих распространенных типов.

Для создания экземпляра на выбор доступны разнообразные конструкторы. Конструктор по умолчанию создает новый экземпляр с определяемой системой емкостью по умолчанию. Однако эта емкость не ограничивает максимального размера создаваемой строки. Вместо этого она представляет объем строковых данных, которые объект может хранить перед тем, как ему понадобится увеличить размер внутреннего буфера, а с ним и допустимую емкость.

При наличии приблизительного представления о размере строящейся строки можно передать этот размер объекту в виде параметра одного из конструкторов, и тогда он инициализирует свой буфер соответствующим образом. Это может помочь экземпляру избежать необходимости в слишком частом повторном размещении буфера в памяти по мере его заполнения.

Кроме того, одна из перегрузок конструктора допускает определение свойства максимальной емкости. По умолчанию максимальная емкость равна System.Int32.MaxValue, что в настоящее время составляет 2 147 483 647 байтов, но точное значение может измениться в процессе развития системы. Если необходимо предохранить буфер от роста свыше некоторой величины, в одной из перегрузок конструктора можно предоставить альтернативную максимальную емкость.

Если операция вставки или добавления потребует увеличения буфера сверх указанного предела, будет сгенерировано исключение ArgumentOutOfRangeException.

Для удобства все методы, которые добавляют и вставляют данные в экземпляр , возвращают ссылку на this. Поэтому операции одного и того же построителя строк можно связывать в цепочки, как показано ниже:

1
2
3
4
5
6
7
8
9
10
11
12
using System;
using System.Text;
public class EntryPoint {
static void Main()  {
 sb = new  ();
sb.Append(" ").Append("является ") .Append("очень ... ") ;
string builtl = sb.ToString();
sb.Append("удобным");
string built2 = sb.ToString();
Console.WriteLine( built1 );
Console.WriteLine( built2 );
}

В приведенном примере с помощью вызова sb.ToString экземпляр по имени sb преобразуется в новый экземпляр System.String по имени builtl. Для достижения максимальной эффективности просто передает ссылку на лежащую в его основе строку, так что создание копии не требуется.

Если хорошо подумать, то часть пользы от оказалась бы под вопросом, если бы он не поступал подобным образом.

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

Однако после вызова .ToString появляется переменная string, a хранит ссылку на ту же самую строку. Поскольку объект string является неизменяемым, в отношении лежащей в основе строки переключается на идиому “копирование при записи”.

Таким образом, в месте, где производится добавление строки к после присваивания переменной builtl, экземпляр должен создать новую копию внутренней строки. При работе с большими строковыми данными посредством очень важно учитывать описанное поведение.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100