В чем разница между изменяемой и неизменной строкой в ​​C #? - PullRequest
187 голосов
/ 25 ноября 2010

В чем разница между изменяемой и неизменной строкой в ​​C #?

Ответы [ 14 ]

312 голосов
/ 25 ноября 2010

Изменяемые и неизменяемые - это английские слова, означающие «может измениться» и «не может измениться» соответственно. Значение слов одинаково в контексте ИТ; т.е.

  • изменяемая строка может быть изменена, а
  • неизменяемая строка не может быть изменена.

Значения этих слов в C # / .NET такие же, как и в других языках программирования / средах, хотя (очевидно) имена типов могут отличаться, как и другие детали.


Для записи:

  • String - это стандартный тип неизменяемой строки C # / .Net
  • StringBuilder - это стандартный тип изменяемой строки C # / .Net

Чтобы «внести изменения» в строку, представленную как C # String, вы фактически создаете новый объект String. Оригинал String не изменяется ... потому что он неизменен.

В большинстве случаев лучше использовать String, потому что это более легкая причина для них; например вам не нужно учитывать возможность того, что какой-то другой поток может «изменить мою строку». Однако, когда вам нужно создать или изменить строку, используя последовательность операций, может быть более эффективно использовать StringBuilder.


И, наконец, для тех людей, которые утверждают, что StringBuilder не является строкой, поскольку она не является неизменной, документация Microsoft описывает StringBuilder таким образом:

"Представляет изменчивую строку символов. Этот класс не может быть унаследован."

181 голосов
/ 25 ноября 2010

String является неизменным

т.е. Строки не могут быть изменены. Когда вы изменяете строку (например, добавляя ее), вы фактически создаете новую строку.

Но StringBuilder не является неизменным (скорее, оно изменчиво)

поэтому, если вам нужно многократно изменять строку, например, несколько конкатенаций, используйте StringBuilder.

44 голосов
/ 25 ноября 2010

Объект является изменяемым, если после его создания его состояние можно изменить, вызывая различные операции с ним, в противном случае он неизменен.

Неизменяемая строка

В C # (и .NET)строка представлена ​​классом System.String.Ключевое слово string является псевдонимом для этого класса.

Класс System.String является неизменным, т. Е. После создания его состояние не может быть изменено .

Поэтому все операции, которые вы выполняете со строкой, такой как Substring, Remove, Replace, конкатенация с использованием оператора «+» и т. Д. Создаст новую строку и вернет ее.

См. Следующую программу для демонстрации -

string str = "mystring";
string newString = str.Substring(2);
Console.WriteLine(newString);
Console.WriteLine(str);

Это выведет строку ''и' mystring 'соответственно.

Для преимуществ неизменности и почему строки являются неизменяемыми check Почему .NET String является неизменяемой? .

Mutable String

Если вы хотите иметь строку, которую хотите часто изменять, вы можете использовать класс StringBuilder. Операции с экземпляром StringBuilder изменят тот же объект .

Для получения дополнительных рекомендаций по , когда использовать StringBuilder, обратитесь к Когда использовать StringBuilder? .

36 голосов
/ 25 ноября 2010

Все string объекты неизменны в C #. Созданные объекты класса string никогда не могут представлять никакого значения, кроме того, с которым они были построены. Все операции, которые, кажется, «изменяют» строку, вместо этого производят новую. Это неэффективно с памятью, но чрезвычайно полезно для уверенности в том, что строка не изменит форму под вами - потому что, пока вы не измените свою ссылку, строка, на которую вы ссылаетесь, никогда не изменится.

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

Если у вас есть изменяемый объект - наиболее похожий на String - StringBuffer - тогда вам нужно сделать его копию, если вы хотите быть абсолютно уверены, что он не изменится из-под вас. Вот почему изменяемые объекты опасны для использования в качестве ключей в любой форме Dictionary или для установки - сами объекты могут измениться, а структура данных не сможет знать, что приведет к повреждению данных, что в конечном итоге приведет к сбою вашей программы. .

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

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

12 голосов
/ 25 ноября 2010

Неизменный:

Когда вы выполняете какую-либо операцию над объектом, он создает новый объект, следовательно, состояние не может быть изменено, как в случае строки.

Изменчивый

Когда вы выполняете какую-либо операцию над объектом, сам объект не изменял созданный новый объект, как в случае StringBuilder

8 голосов
/ 19 сентября 2013

В .NET System.String (иначе строка) является неизменным объектом.Это означает, что когда вы создаете объект, вы не можете изменить его значение впоследствии.Вы можете воссоздать только неизменный объект.

System.Text.StringBuilder является непостоянным эквивалентом System.String, и вы можете изменить его значение

Например:

class Program
{
    static void Main(string[] args)
    {

        System.String str = "inital value";
        str = "\nsecond value";
        str = "\nthird value";

        StringBuilder sb = new StringBuilder();
        sb.Append("initial value");
        sb.AppendLine("second value");
        sb.AppendLine("third value");
    }
}

Создает следующий MSIL: Если вы исследуетекод.Вы увидите, что всякий раз, когда вы изменяете объект System.String, вы фактически создаете новый.Но в System.Text.StringBuilder, когда вы изменяете значение текста, вы не воссоздаете объект.

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       62 (0x3e)
  .maxstack  2
  .locals init ([0] string str,
           [1] class [mscorlib]System.Text.StringBuilder sb)
  IL_0000:  nop
  IL_0001:  ldstr      "inital value"
  IL_0006:  stloc.0
  IL_0007:  ldstr      "\nsecond value"
  IL_000c:  stloc.0
  IL_000d:  ldstr      "\nthird value"
  IL_0012:  stloc.0
  IL_0013:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0018:  stloc.1
  IL_0019:  ldloc.1
  IL_001a:  ldstr      "initial value"
  IL_001f:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0024:  pop
  IL_0025:  ldloc.1
  IL_0026:  ldstr      "second value"
  IL_002b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::AppendLine(string)
  IL_0030:  pop
  IL_0031:  ldloc.1
  IL_0032:  ldstr      "third value"
  IL_0037:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::AppendLine(string)
  IL_003c:  pop
  IL_003d:  ret
} // end of method Program::Main
6 голосов
/ 22 мая 2015

Строки являются изменяемыми, потому что .NET используют пул строк за сценой. Это значит:

string name = "My Country";
string name2 = "My Country";

И имя, и имя2 относятся к одной и той же ячейке памяти из пула строк. Теперь предположим, что вы хотите изменить name2 на:

name2 = "My Loving Country";

Она будет искать в пуле строк строку «Моя любящая страна», если она будет найдена, вы получите ссылку на нее, а в пуле строк будет создана новая мудрая строка «Моя любящая страна», а name2 получит ссылку на нее. , Но весь этот процесс " Моя страна " не был изменен, потому что другая переменная, такая как name , все еще использует его. И это причина, по которой строки НЕЗАМЕТНЫ .

StringBuilder работает по-другому и не использует пул строк. Когда мы создаем любой экземпляр StringBuilder:

var address  = new StringBuilder(500);

Он выделяет кусок памяти размером 500 байт для этого экземпляра, и все операции просто изменяют эту область памяти, и эта память не используется другими объектами. И именно поэтому StringBuilder равен MUTABLE .

Надеюсь, это поможет.

5 голосов
/ 09 августа 2015

Нет, на самом деле.Класс String является изменяемым.

unsafe
{
    string foo = string.Copy("I am immutable.");
    fixed (char* pChar = foo)
    {
        char* pFoo = pChar;

        pFoo[5] = ' ';
        pFoo[6] = ' ';
    }

    Console.WriteLine(foo); // "I am   mutable."
}

Этот вид логики выполняется все время в классах String и StringBuilder.Они просто выделяют новую строку каждый раз, когда вы вызываете Concat, Substring и т. Д., И используете арифметику указателей для копирования в новую строку.Строки просто не видоизменяются сами по себе, поэтому их считают «неизменяемыми».


Кстати, не пытайтесь сделать это со строковыми литералами, иначе вы испортите свойпрограмма:

string bar = "I am a string.";

fixed (char* pChar = bar)
{
    char* pBar = pChar;

    pBar[2] = ' ';
}

string baz = "I am a string.";

Console.WriteLine(baz); // "I  m a string."

Это потому, что строковые литералы интернированы в настольном .NET Framework;другими словами, bar и baz указывают на одну и ту же строку, поэтому изменение одного приведет к изменению другого.Это все прекрасно, но если вы используете неуправляемую платформу, такую ​​как WinRT, в которой отсутствует интернирование строк.

2 голосов
/ 30 ноября 2010

Для пояснения, в C # (или вообще в .NET) нет такой вещи, как изменяемая строка. Другие языки поддерживают изменяемые строки (строки, которые могут изменяться), а платформа .NET - нет.

Таким образом, правильный ответ на ваш вопрос - ВСЕ строки неизменны в C #.

строка имеет конкретное значение. Строковое ключевое слово "string" - это просто ярлык для объекта, созданного из класса System.String. Все объекты, созданные из строкового класса, ВСЕГДА неизменны.

Если вам нужно изменяемое представление текста, вам нужно использовать другой класс, например StringBuilder. StringBuilder позволяет итеративно создавать коллекцию «слов», а затем преобразовывать ее в строку (снова неизменяемую).

1 голос
/ 08 июля 2012

Значение данных не может быть изменено.Примечание. Значение переменной может быть изменено, но исходное значение неизменяемых данных было отброшено, и в памяти было создано новое значение данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...