Qual é a diferença entre uma sequência mutável e imutável em C #?

Respostas:

313

Mutável e imutável são as palavras em inglês que significam "pode ​​mudar" e "não pode mudar", respectivamente. O significado das palavras é o mesmo no contexto de TI; ie

  • uma string mutável pode ser alterada e
  • uma sequência imutável não pode ser alterada.

O significado dessas palavras é o mesmo em C # / .NET e em outras linguagens / ambientes de programação, embora (obviamente) os nomes dos tipos possam diferir, assim como outros detalhes.


Para o registro:

  • String é o tipo de sequência imutável C # / .Net padrão
  • StringBuilder é o tipo de sequência mutável C # / .Net padrão

Para "efetuar uma alteração" em uma sequência representada como C # String, você realmente cria um novo Stringobjeto. O original Stringnão é alterado ... porque é imutável.

Na maioria dos casos, é melhor usar Stringporque é uma razão mais fácil sobre eles; por exemplo, você não precisa considerar a possibilidade de que algum outro thread possa "alterar minha string". No entanto, quando você precisa construir ou modificar uma string usando uma sequência de operações, pode ser mais eficiente usar a StringBuilder.


E, finalmente, para as pessoas que afirmam que a StringBuildernão é uma sequência porque não é imutável, a documentação da Microsoft descreve StringBuilderassim:

"Representa uma sequência mutável de caracteres. Esta classe não pode ser herdada."

Stephen C
fonte
182

String é imutável

isto é, strings não podem ser alteradas. Quando você altera uma sequência (adicionando a ela, por exemplo), na verdade você está criando uma nova sequência.

Mas StringBuildernão é imutável (é mutável)

portanto, se você precisar alterar uma sequência várias vezes, como várias concatenações, use StringBuilder.

Pankaj Agarwal
fonte
4
O que acontece se você concatenar seqüências imutáveis ​​muitas vezes? Cargas de uso de memória para seqüências de caracteres sem referências? Ou apenas devagar?
quer
13
@ Rudie - ambos. Cada concatenação cria um novo objeto String e copia todos os caracteres das duas seqüências de entrada. Leva ao O(N^2)comportamento ...
Stephen C
@StephenC explicou com as palavras-chave.
Kent Liau
6
se você tiver que alterar uma string muitas vezes, como várias concatenações, em seguida, usar StringBuilder ... Isso clareou minha mente totalmente obrigado ...
katmanco
45

Um objeto é mutável se, uma vez criado, seu estado puder ser alterado chamando várias operações nele, caso contrário, é imutável.

String imutável

Em C # (e .NET), uma seqüência de caracteres é representada pela classe System.String. A stringpalavra-chave é um alias para esta classe.

A classe System.String é imutável, ou seja, uma vez criado, seu estado não pode ser alterado .

Assim, todas as operações que você executar em uma string como Substring, Remove, Replace, concatenação usando operador '+' etc irá criar uma nova seqüência e devolvê-lo.

Veja o seguinte programa para demonstração -

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

Isso imprimirá 'string' e 'mystring' respectivamente.

Para os benefícios da imutabilidade e por que a string é imutável, verifique Por que o .NET String é imutável? .

String mutável

Se você deseja ter uma string que deseja modificar frequentemente, pode usar a StringBuilderclasse As operações em uma StringBuilder instância modificarão o mesmo objeto .

Para obter mais conselhos sobre quando usar, StringBuilder consulte Quando usar o StringBuilder? .

Unmesh Kondolikar
fonte
Linda explicação!
Hari
36

Todos os stringobjetos são imutáveis ​​em C #. Objetos da classe string, uma vez criados, nunca podem representar outro valor além daquele com o qual foram construídos. Todas as operações que parecem "alterar" uma sequência produzem uma nova. Isso é ineficiente com a memória, mas extremamente útil em relação à capacidade de confiar que uma string não será alterada sob você - porque, desde que você não altere sua referência, a string a que se refere nunca mudará.

Um objeto mutável, por outro lado, possui campos de dados que podem ser alterados. Um ou mais de seus métodos alteram o conteúdo do objeto ou possuem uma Propriedade que, quando gravada, altera o valor do objeto.

Se você tem um objeto mutável - o mais semelhante a String é StringBuffer-, é necessário fazer uma cópia dele se quiser ter certeza absoluta de que ele não será alterado. É por isso que objetos mutáveis ​​são perigosos para usar como chaves em qualquer forma Dictionaryou conjunto - os próprios objetos podem mudar e a estrutura de dados não tem como saber, levando a dados corrompidos que, eventualmente, travariam seu programa.

No entanto, você pode alterar seu conteúdo - portanto, é muito, muito mais eficiente em termos de memória do que fazer uma cópia completa, porque você queria alterar um único caractere ou algo semelhante.

Geralmente, a coisa certa a fazer é usar objetos mutáveis ​​enquanto você cria algo e objetos imutáveis ​​quando terminar. Isso se aplica a objetos que têm formas imutáveis, é claro; a maioria das coleções não. Muitas vezes, é útil fornecer formas de coleções somente leitura, o que equivale a imutável, ao enviar o estado interno da sua coleção para outros contextos; caso contrário, algo pode levar esse valor de retorno, fazer alguma coisa e corromper seu dados.

Adam Norberg
fonte
12

Imutável:

Quando você faz alguma operação em um objeto, ele cria um novo objeto, portanto, o estado não é modificável, como no caso de uma string.

Mutável

Quando você executa alguma operação em um objeto, o próprio objeto não modifica nenhum novo objeto criado, como no caso de StringBuilder

TalentTuner
fonte
8

No .NET System.String (aka string) é um objeto imutável. Isso significa que quando você cria um objeto, não é possível alterar seu valor posteriormente. Você só pode recriar um objeto imutável.

System.Text.StringBuilder é equivalente mutável de System.String e você pode alterar seu valor

Por exemplo:

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");
    }
}

Gera o seguinte MSIL: Se você investigar o código. Você verá que sempre que criar um objeto de System.String, estará criando um novo. Mas no System.Text.StringBuilder sempre que você altera o valor do texto, você não recria o objeto.

.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
cahit beyaz
fonte
5
Ummm ... esse código desmontado mostra apenas que as atribuições do ponteiro estão sendo feitas e os métodos estão sendo chamados. Não tem (quase) nada a ver com mutável versus imutável. (Ele me escapa por que algumas pessoas pensam que desmontar alguns códigos de exemplo irrelevante vai ajudar as pessoas a entender esse tipo de coisa Para começar, a maioria dos programadores não são fluentes em código CLI..)
Stephen C
6

As strings são mutáveis ​​porque o .NET usa o pool de strings nos bastidores. Isso significa :

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

O nome e o nome2 estão se referindo ao mesmo local de memória do conjunto de cadeias. Agora, suponha que você queira alterar o nome2 para:

name2 = "My Loving Country";

Ele procurará no conjunto de strings a sequência "My Loving Country"; se encontrado, você obterá a referência dela; outra nova sequência sábia "My Loving Country" será criada no pool de strings e name2 obterá referência. Mas todo esse processo " Meu país " não foi alterado porque outra variável como nome ainda o está usando. E essa é a razão pela qual a sequência é IMMUTABLE .

StringBuilder funciona de maneira diferente e não usa pool de strings. Quando criamos qualquer instância do StringBuilder:

var address  = new StringBuilder(500);

Ele aloca um pedaço de memória de tamanho 500 bytes para esta instância e todas as operações apenas modificam esse local de memória e essa memória não é compartilhada com nenhum outro objeto. E essa é a razão pela qual StringBuilder é MUTABLE .

Eu espero que isso ajude.

Rahul Garg
fonte
5

Nenhuma, na verdade. A classe String é mutável.

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."
}

Esse tipo de lógica é feito o tempo todo nas classes String e StringBuilder, na verdade. Eles apenas alocam uma nova string sempre que você chama Concat, Substring, etc. e usam a aritmética do ponteiro para copiar para a nova string. As strings simplesmente não se transformam, por isso são consideradas "imutáveis".


A propósito, não tente fazer isso com literais de string ou você estragará o seu programa:

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."

Isso ocorre porque literais de seqüência de caracteres são internados no .NET Framework da área de trabalho; em outras palavras, bare bazaponte para exatamente a mesma string, portanto, uma mutação mutará a outra. Tudo isso é ótimo e elegante, se você estiver usando uma plataforma não gerenciada como o WinRT, que não possui internação de strings.

James Ko
fonte
1
Bem, sim. Se você quebrar as regras quebrando abstrações abertas que deveriam ser fechadas, quase nada será imutável. Você pode fazer coisas análogas em Java usando reflexão desagradável ... mas o JLS afirma que o comportamento que você recebe é indefinido.
Stephen C
2

Para esclarecer, não existe uma string mutável em C # (ou .NET em geral). Outros idiomas suportam seqüências de caracteres mutáveis ​​(sequência que pode ser alterada), mas a estrutura .NET não.

Portanto, a resposta correta para sua pergunta é que TODAS as strings são imutáveis ​​em C #.

string tem um significado específico. A palavra-chave minúscula "string" é apenas um atalho para um objeto instanciado da classe System.String. Todos os objetos criados a partir da classe string são SEMPRE imutáveis.

Se você deseja uma representação mutável do texto, precisará usar outra classe como StringBuilder. O StringBuilder permite criar iterativamente uma coleção de 'palavras' e depois convertê-lo em uma string (mais uma vez imutável).

Gerald Davis
fonte
Desculpe, mas a documentação da Microsoft StringBuildercontradiz isso: consulte msdn.microsoft.com/en-us/library/…
Stephen C
1

O valor dos dados não pode ser alterado. Nota: O valor da variável pode ser alterado, mas o valor original dos dados imutáveis ​​foi descartado e um novo valor de dados foi criado na memória.

Vikas Kumar
fonte
1

em detalhes de implementação.

System.String do CLR2 é mutável. StringBuilder.Append chamando String.AppendInplace (método privado)

O System.String do CLR4 é imutável. StringBuilder tem matriz Char com chunking.

kazuk
fonte
0

De http://yassershaikh.com/what-is-the-difference-between-strings-and-stringbuilder-in-c-net/

Resposta curta: String é imutável - enquanto StringBuilder é mutável.

O que isso significa ? O Wiki diz: No orientado a objetos, um objeto imutável é um objeto cujo estado não pode ser modificado após a criação. Isso contrasta com um objeto mutável, que pode ser modificado após a criação.

Na documentação da classe StringBuilder:

O objeto String é imutável. Sempre que você usa um dos métodos da classe System.String, cria um novo objeto de seqüência de caracteres na memória, o que requer uma nova alocação de espaço para esse novo objeto.

Nas situações em que você precisa executar modificações repetidas em uma string, a sobrecarga associada à criação de um novo objeto String pode ser cara.

A classe System.Text.StringBuilder pode ser usada quando você deseja modificar uma seqüência de caracteres sem criar um novo objeto. Por exemplo, o uso da classe StringBuilder pode aumentar o desempenho ao concatenar várias seqüências juntas em um loop.

Yasser Shaikh
fonte
0

Aqui está o exemplo para o Construtor de Sequências Imutáveis ​​e Mutáveis

        Console.WriteLine("Mutable String Builder");
        Console.WriteLine("....................................");
        Console.WriteLine();
        StringBuilder sb = new StringBuilder("Very Good Morning");
        Console.WriteLine(sb.ToString());
        sb.Remove(0, 5);
        Console.WriteLine(sb.ToString());

        Console.WriteLine();

        Console.WriteLine("Immutable String");
        Console.WriteLine("....................................");
        Console.WriteLine();
        string s = "Very Good Morning";
        Console.WriteLine(s);
        s.Substring(0, 5);
        Console.WriteLine(s);
        Console.ReadLine();
Gokul
fonte
Será muito bom se você pode fornecer a saída bem @Gokul :)
Roy Lee
Substring não altera o valor subjacente. Ele retorna apenas um valor.
Kye 07/07
@Kye e por quê? porque as cordas são :) imutável
LuckyLikey
Seu código de 2 linhas -: s.Substring (0, 5); Console.WriteLine (s); Aqui s.substring () não altera s. este exemplo não mostra se a sequência é imutável.
Dhananjay
0

String em C # é imutável. Se você concatená-lo com qualquer string, na verdade você está criando uma nova string, que é um novo objeto de string! Mas StringBuilder cria uma sequência mutável.

Md Shahriar
fonte
0

StringBuilder é uma opção melhor para concaturar uma enorme sequência de dados, porque o StringBuilder é um tipo de sequência mutável e o objeto StringBuilder é um tipo imutável, o que significa que o StringBuilder nunca cria uma nova instância do objeto enquanto concata a sequência.

Se estivermos usando string em vez de StringBuilder para obter concatenação, ele criará sempre uma nova instância na memória.

Sher Singh
fonte