A string
экземпляр является неизменным.Вы не можете изменить его после того, как он был создан.Любая операция, которая, кажется, изменяет строку, вместо этого возвращает новый экземпляр:
string foo = "Foo";
// returns a new string instance instead of changing the old one
string bar = foo.Replace('o', 'a');
string baz = foo + "bar"; // ditto here
Неизменяемые объекты имеют некоторые хорошие свойства, такие как их можно использовать в потоках, не опасаясь проблем с синхронизацией, или что вы можете просто раздать свойзакрытые поля поддержки напрямую, не опасаясь, что кто-то изменяет объекты, которые он не должен изменять (см. массивы или изменяемые списки, которые часто необходимо скопировать перед возвратом, если это нежелательно).Но при неосторожном использовании они могут создавать серьезные проблемы с производительностью (как почти все - если вам нужен пример из языка, который гордится скоростью выполнения, тогда посмотрите на функции манипулирования строками в Си).
Когда вам нужен изменяемая строка, такая как та, которую вы строите по частям или где вы меняете много вещей, тогда вам понадобится StringBuilder
, который представляет собой буфер символов, который может бытьизменилось.По большей части это влияет на производительность.Если вам нужна изменяемая строка и вместо этого вы делаете это с обычным экземпляром string
, то в конечном итоге вы создадите и уничтожите множество объектов без необходимости, тогда как сам экземпляр StringBuilder
изменится, что устранит необходимость во многих новых объектах.
Простой пример: следующее заставит многих программистов съежиться от боли:
string s = string.Empty;
for (i = 0; i < 1000; i++) {
s += i.ToString() + " ";
}
В итоге вы создадите 2001 строк, 2000 из которых отброшены.Тот же пример с использованием StringBuilder:
StringBuilder sb = new StringBuilder();
for (i = 0; i < 1000; i++) {
sb.Append(i);
sb.Append(' ');
}
Это должно значительно снизить нагрузку на распределитель памяти: -)
Однако следует отметить, что компилятор C # достаточно умен, когда он появляется.в строки.Например, следующая строка
string foo = "abc" + "def" + "efg" + "hij";
будет присоединена компилятором, оставив только одну строку во время выполнения.Аналогично, такие строки, как
string foo = a + b + c + d + e + f;
, будут переписаны в
string foo = string.Concat(a, b, c, d, e, f);
, поэтому вам не придется платить за пять бессмысленных конкатенаций, которые были бы наивным способом обработки этого.Это не спасет вас в циклах, как описано выше (если только компилятор не развернет цикл, но я думаю, что на самом деле это может сделать только JIT, и лучше не ставить на это).