StringBuilder C#
Всем доброго времени суток, на связи Алексей Гулынин. В прошлой статье мы узнали про явное и неявное преобразование в C#. В данной статье я бы хотел поговорить про класс StringBuilder в C#. Вначале разберем то, как мы обычно складываем строки.
Для сложения (склейки) строк в C# перегружен оператор "+". Это оператор конкатенации строк. Допустим у нас имеется 4 строки, которые мы хотим склеить в одну. Напишем пример кода:
static void Main(string[] args) { string s1 = "Hello"; string s2 = "my"; string s3 = "dear"; string s4 = "friend"; string result = s1 + ", " + s2 + " " + s3 + " " + s4; Console.WriteLine(result); Console.ReadLine(); }
Код работает, результат выводится. Но оптимально ли так делать? Давайте разберем другой способ склеивания строк — это как раз использование класса StringBuilder. Напишем код:
static void Main(string[] args) { string s1 = "Hello"; string s2 = "my"; string s3 = "dear"; string s4 = "friend"; StringBuilder result = new StringBuilder(); result.AppendLine(s1 + ", " + s2 + " " + s3 + " " + s4); Console.WriteLine(result); Console.ReadLine(); }
Вроде бы отличия нет. Результат выводится одинаковый в обоих случаях. Главный вопрос — одинаковая ли производительность у обоих способов?
Первый способ сборки строк в .NET плох. Объекта класса String является неизменяемым объектом (immutable object). Каждый раз, когда мы выполняем операцию — мы не меняем существующие строки, а создаём новую строку. Объясню подробнее на первом примере. У нас сначала будет создана строка "Hello, ", затем строка "Hello, my", затем строка "Hello, my ", затем строка "Hello, my dear", "Hello, my dear " и "Hello, my dear friend". Все эти строки будут висеть в памяти, что нам совсем не нужно. Для решения данной проблемы как раз и используется класс StringBuilder, который представляет из себя изменяемую строку. Здесь вместо оператора конкатенации можно использовать методы Append() и AppendLine(), которые будут не новый объект создавать, а модифицировать существующий.
Второй способ потребляет меньше памяти и работает гораздо быстрее.
Попробуем на следующим примере продемонстрировать разницу в производительности данных методов:
static void Main(string[] args) { { string result = ""; DateTime dt = DateTime.Now; for (int i = 1; i < 100000; i++) { result = result + i.ToString(); } Console.WriteLine("Время скрипта {0}", DateTime.Now - dt); Console.ReadLine(); //Время скрипта было 15.7303146 секунд } { StringBuilder result = new StringBuilder(); DateTime dt = DateTime.Now; for (int i = 1; i < 100000; i++) { result.Append(i.ToString()); } Console.WriteLine("Время скрипта {0}", DateTime.Now - dt); Console.ReadLine(); //Время скрипта было 0.020004 секунд } }
Что мы делаем в данном скрипте: в цикле из 100000 элементов мы к каждой строке прибавляем число, т.е. у нас будет такие строки на каждой итерации: 1, 12, 123, 1234 и т.д. (происходит склейка строк). В первом случае у нас будет создано 100000 строк (объектов), которые будут висеть в памяти. Во втором случае будет изменяться существующий объект.
На данном примере мы убедились, что использование класса StringBuilder в C# в разы повышает производительность.
В качестве домашнего задания протестируйте работу данного скрипта.