Was ist der Unterschied zwischen einer veränderlichen und einer unveränderlichen Zeichenfolge in C #?


190

Was ist der Unterschied zwischen einer veränderlichen und einer unveränderlichen Zeichenfolge in C #?



6
Es ist nicht identisch. Sehr ähnlich, aber das ist nicht dasselbe wie identisch.
Marcelo Cantos

2
Verwandte Frage zu den Interna von StringBuilder stackoverflow.com/q/3564906/38206
Brian Rasmussen

Antworten:


313

Veränderlich und unveränderlich sind englische Wörter, die "können sich ändern" bzw. "können sich nicht ändern" bedeuten. Die Bedeutung der Wörter ist im IT-Kontext dieselbe. dh

  • Eine veränderbare Zeichenfolge kann geändert werden
  • Eine unveränderliche Zeichenfolge kann nicht geändert werden.

Die Bedeutungen dieser Wörter sind in C # / .NET dieselben wie in anderen Programmiersprachen / -umgebungen, obwohl (offensichtlich) die Namen der Typen und andere Details unterschiedlich sein können.


Für die Aufzeichnung:

  • String ist der Standardtyp für unveränderliche C # / .Net-Zeichenfolgen
  • StringBuilder ist der standardmäßige veränderbare C # / .Net-Zeichenfolgentyp

Um eine Änderung an einer als C # dargestellten Zeichenfolge "vorzunehmen" String, erstellen Sie tatsächlich ein neues StringObjekt. Das Original Stringwird nicht verändert ... weil es unveränderlich ist.

In den meisten Fällen ist es besser zu verwenden, Stringweil es einfacher ist, sie zu verstehen. Sie müssen beispielsweise nicht die Möglichkeit in Betracht ziehen, dass ein anderer Thread "meine Zeichenfolge ändert". Wenn Sie jedoch eine Zeichenfolge mithilfe einer Folge von Operationen erstellen oder ändern müssen, ist die Verwendung von a möglicherweise effizienter StringBuilder.


Und schließlich beschreibt StringBuilderdie Microsoft- Dokumentation für diejenigen, die behaupten, dass a keine Zeichenfolge ist, weil es nicht unveränderlich ist, Folgendes StringBuilder:

"Stellt eine veränderbare Zeichenfolge dar . Diese Klasse kann nicht vererbt werden."


182

String ist unveränderlich

dh Strings können nicht geändert werden. Wenn Sie eine Zeichenfolge ändern (indem Sie sie beispielsweise hinzufügen), erstellen Sie tatsächlich eine neue Zeichenfolge.

Ist StringBuilderaber nicht unveränderlich (vielmehr ist es veränderlich)

Wenn Sie also eine Zeichenfolge mehrmals ändern müssen, z. B. mehrere Verkettungen, verwenden Sie StringBuilder.


4
Was passiert, wenn Sie unveränderliche Zeichenfolgen oft zusammenfassen? Viel Speicherplatz für Strings ohne Referenzen? Oder nur langsam?
Rudie

13
@ Rudie - beides. Jede Verkettung erstellt ein neues String-Objekt und kopiert alle Zeichen beider Eingabezeichenfolgen. Führt zu O(N^2)Verhalten ...
Stephen C

@StephenC erklärt mit den Schlüsselwörtern.
Kent Liau

6
Wenn Sie einen String mehrmals ändern müssen, z. B. mehrere Verkettungen, dann verwenden Sie StringBuilder ... Das hat mich völlig
klar gemacht,

45

Ein Objekt kann geändert werden, wenn sein Status nach seiner Erstellung durch Aufrufen verschiedener Operationen geändert werden kann. Andernfalls ist es unveränderlich.

Unveränderliche Zeichenfolge

In C # (und .NET) wird eine Zeichenfolge durch die Klasse System.String dargestellt. Das stringSchlüsselwort ist ein Alias ​​für diese Klasse.

Die System.String-Klasse ist unveränderlich, dh sobald sie erstellt wurde, kann ihr Status nicht mehr geändert werden .

So sind alle Operationen , die an einer Schnur wie Substring, Remove, Replace, Verkettung mit ‚+‘ Operator usw. wird eine neue Zeichenfolge erstellen und es zurück.

Demonstrieren Sie das folgende Programm -

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

Dadurch werden "string" bzw. "mystring" gedruckt.

Für die Vorteile der Unveränderlichkeit und warum Zeichenfolgen unveränderlich sind, überprüfen Sie, warum .NET- Zeichenfolgen unveränderlich sind. .

Veränderbare Zeichenfolge

Wenn Sie eine Zeichenfolge haben möchten, die Sie häufig ändern möchten, können Sie die StringBuilderKlasse verwenden. Operationen an einer StringBuilder Instanz ändern dasselbe Objekt .

Weitere Hinweise zur Verwendung finden Sie StringBuilder unter Wann wird StringBuilder verwendet? .


Schöne Erklärung!
Hari

36

Alle stringObjekte sind in C # unveränderlich. stringEinmal erstellte Objekte der Klasse können niemals einen anderen Wert als den darstellen, mit dem sie erstellt wurden. Alle Operationen, die eine Zeichenfolge zu "ändern" scheinen, erzeugen stattdessen eine neue. Dies ist ineffizient mit dem Speicher, aber äußerst nützlich, um darauf vertrauen zu können, dass sich die Form einer Zeichenfolge unter Ihnen nicht ändert. Solange Sie Ihre Referenz nicht ändern, ändert sich die Zeichenfolge, auf die verwiesen wird, niemals.

Ein veränderliches Objekt verfügt dagegen über Datenfelder, die geändert werden können. Eine oder mehrere seiner Methoden ändern den Inhalt des Objekts oder haben eine Eigenschaft, die beim Schreiben den Wert des Objekts ändert.

Wenn Sie ein veränderbares Objekt haben - das String am ähnlichsten ist StringBuffer-, müssen Sie eine Kopie davon erstellen, wenn Sie absolut sicher sein möchten, dass es sich nicht unter Ihnen ändert. Aus diesem Grund ist es gefährlich, veränderbare Objekte als Schlüssel für jede Form Dictionaryoder Menge zu verwenden. Die Objekte selbst können sich ändern, und die Datenstruktur kann nicht erkannt werden, was zu beschädigten Daten führt, die Ihr Programm schließlich zum Absturz bringen würden.

Sie können jedoch den Inhalt ändern. Dies ist viel, viel speichereffizienter als das Erstellen einer vollständigen Kopie, da Sie ein einzelnes Zeichen oder ähnliches ändern möchten.

Im Allgemeinen ist es richtig, veränderbare Objekte zu verwenden, während Sie etwas erstellen, und unveränderliche Objekte, wenn Sie fertig sind. Dies gilt natürlich für Objekte mit unveränderlichen Formen; Die meisten Sammlungen tun dies nicht. Es ist jedoch oft nützlich, schreibgeschützte Formen von Sammlungen bereitzustellen, was unveränderlich ist, wenn der interne Status Ihrer Sammlung an andere Kontexte gesendet wird. Andernfalls kann etwas diesen Rückgabewert annehmen, etwas dagegen tun und Ihre beschädigen Daten.


12

Unveränderlich:

Wenn Sie eine Operation an einem Objekt ausführen, wird ein neues Objekt erstellt, sodass der Status nicht wie im Fall einer Zeichenfolge geändert werden kann.

Veränderlich

Wenn Sie eine Operation an einem Objekt ausführen, hat das Objekt selbst kein neues Objekt geändert, das wie im Fall von StringBuilder erstellt wurde


8

In .NET ist System.String (auch bekannt als Zeichenfolge) ein unveränderliches Objekt. Das heißt, wenn Sie ein Objekt erstellen, können Sie dessen Wert danach nicht mehr ändern. Sie können nur ein unveränderliches Objekt neu erstellen.

System.Text.StringBuilder ist ein veränderbares Äquivalent zu System.String, und Sie können seinen Wert ändern

Beispielsweise:

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

Erzeugt folgende MSIL: Wenn Sie den Code untersuchen. Sie werden sehen, dass Sie jedes Mal, wenn Sie ein Objekt von System.String ändern, tatsächlich ein neues erstellen. In System.Text.StringBuilder wird das Objekt jedoch nicht neu erstellt, wenn Sie den Wert von Text ändern.

.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

5
Ummm ... dieser zerlegte Code zeigt nur, dass Zeigerzuweisungen vorgenommen und Methoden aufgerufen werden. Es hat (fast) nichts mit veränderlich oder unveränderlich zu tun. (Es entgeht mir, warum einige Leute denken, dass das Zerlegen eines irrelevanten Beispielcodes den Leuten helfen wird, diese Art von Dingen zu verstehen. Zunächst sprechen die meisten Programmierer den CLI-Code nicht fließend.)
Stephen C

6

Zeichenfolgen sind veränderbar, da .NET hinter den Kulissen einen Zeichenfolgenpool verwendet. Es bedeutet :

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

Sowohl name als auch name2 beziehen sich auf denselben Speicherort aus dem Zeichenfolgenpool. Angenommen, Sie möchten name2 in Folgendes ändern:

name2 = "My Loving Country";

Es wird im Zeichenfolgenpool nach der Zeichenfolge "My Loving Country" gesucht. Wenn sie gefunden wird, erhalten Sie die Referenz. Eine andere neue Zeichenfolge "My Loving Country" wird im Zeichenfolgenpool erstellt und name2 erhält eine Referenz davon. Aber dieser ganze Prozess " Mein Land " wurde nicht geändert, weil andere Variablen wie der Name ihn noch verwenden. Und das ist der Grund, warum Zeichenfolgen IMMUTIERBAR sind .

StringBuilder funktioniert anders und verwendet keinen String-Pool. Wenn wir eine Instanz von StringBuilder erstellen:

var address  = new StringBuilder(500);

Es weist dieser Instanz einen Speicherblock mit einer Größe von 500 Byte zu, und alle Vorgänge ändern lediglich diesen Speicherort und diesen Speicher, der nicht mit einem anderen Objekt geteilt wird. Und das ist der Grund , warum Stringbuilder ist Veraenderlich .

Ich hoffe es wird helfen.


5

Eigentlich keine. Die String-Klasse ist veränderbar.

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

Diese Art von Logik wird tatsächlich die ganze Zeit in den Klassen String und StringBuilder ausgeführt. Sie weisen einfach jedes Mal eine neue Zeichenfolge zu, wenn Sie Concat, Substring usw. aufrufen, und verwenden Zeigerarithmetik, um in die neue Zeichenfolge zu kopieren. Saiten mutieren einfach nicht selbst, weshalb sie als "unveränderlich" gelten.


Versuchen Sie dies übrigens nicht mit String-Literalen, da Sie sonst Ihr Programm durcheinander bringen:

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

Dies liegt daran, dass Zeichenfolgenliterale im Desktop .NET Framework interniert sind. Mit anderen Worten, barund bazzeigen Sie auf genau dieselbe Zeichenfolge. Wenn Sie also eine mutieren, wird die andere mutiert. Dies ist jedoch alles in Ordnung, wenn Sie eine nicht verwaltete Plattform wie WinRT verwenden, auf der es an String-Internierung mangelt.


1
Nun ja. Wenn Sie gegen die Regeln verstoßen, indem Sie Abstraktionen aufbrechen, die geschlossen werden sollen, ist fast nichts unveränderlich. Sie können in Java analoge Dinge mit böser Reflexion tun ... aber das JLS gibt an, dass das Verhalten, das Sie erhalten, undefiniert ist.
Stephen C

2

Zur Verdeutlichung gibt es in C # (oder .NET im Allgemeinen) keine veränderbare Zeichenfolge. Andere Sprachen unterstützen veränderbare Zeichenfolgen (Zeichenfolgen, die sich ändern können), das .NET-Framework jedoch nicht.

Die richtige Antwort auf Ihre Frage lautet also: ALLE Zeichenfolgen sind in C # unveränderlich.

Zeichenfolge hat eine bestimmte Bedeutung. Das Schlüsselwort "string" in Kleinbuchstaben ist lediglich eine Verknüpfung für ein Objekt, das aus der System.String-Klasse instanziiert wurde. Alle aus der Zeichenfolgenklasse erstellten Objekte sind IMMER unveränderlich.

Wenn Sie eine veränderbare Darstellung von Text wünschen, müssen Sie eine andere Klasse wie StringBuilder verwenden. Mit StringBuilder können Sie iterativ eine Sammlung von 'Wörtern' erstellen und diese dann in eine Zeichenfolge konvertieren (wieder unveränderlich).


Entschuldigung, aber die Microsoft-Dokumentation StringBuilderwiderspricht dem: siehe msdn.microsoft.com/en-us/library/…
Stephen C

1

Der Datenwert darf nicht geändert werden. Hinweis: Der Variablenwert kann geändert werden, der ursprüngliche unveränderliche Datenwert wurde jedoch verworfen und ein neuer Datenwert im Speicher erstellt.


1

im Implementierungsdetail.

Der System.String von CLR2 ist veränderbar. StringBuilder.Append ruft String.AppendInplace auf (private Methode)

Der System.String von CLR4 ist unveränderlich. StringBuilder haben ein Char-Array mit Chunking.


0

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

Kurze Antwort: String ist unveränderlich - während StringBuilder veränderlich ist.

Was bedeutet das ? Das Wiki sagt: Im objektorientierten ist ein unveränderliches Objekt ein Objekt, dessen Status nach seiner Erstellung nicht mehr geändert werden kann. Dies steht im Gegensatz zu einem veränderlichen Objekt, das nach seiner Erstellung geändert werden kann.

Aus der Dokumentation zur StringBuilder-Klasse:

Das String-Objekt ist unveränderlich. Jedes Mal, wenn Sie eine der Methoden in der System.String-Klasse verwenden, erstellen Sie ein neues Zeichenfolgenobjekt im Speicher, für das eine neue Speicherplatzzuweisung für dieses neue Objekt erforderlich ist.

In Situationen, in denen Sie wiederholt Änderungen an einer Zeichenfolge vornehmen müssen, kann der mit dem Erstellen eines neuen Zeichenfolgenobjekts verbundene Aufwand kostspielig sein.

Die System.Text.StringBuilder-Klasse kann verwendet werden, wenn Sie eine Zeichenfolge ändern möchten, ohne ein neues Objekt zu erstellen. Die Verwendung der StringBuilder-Klasse kann beispielsweise die Leistung steigern, wenn viele Zeichenfolgen in einer Schleife miteinander verknüpft werden.


0

Hier ist das Beispiel für den Builder für unveränderliche Zeichenfolgen und veränderbare Zeichenfolgen

        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();

Es wird sehr schön sein, wenn Sie die Ausgabe auch @Gokul bereitstellen können :)
Roy Lee

Teilzeichenfolge ändert den zugrunde liegenden Wert nicht. Es wird nur ein Wert zurückgegeben.
Kye

@Kye und warum? weil Saiten unveränderlich sind :)
LuckyLikey

Ihr 2-Zeilen-Code -: s.Substring (0, 5); Console.WriteLine (s); Hier ändert sich s.substring () nicht s. Dieses Beispiel zeigt nicht, ob die Zeichenfolge unveränderlich ist.
Dhananjay

0

String in C # ist unveränderlich. Wenn Sie es mit einer Zeichenfolge verketten, erstellen Sie tatsächlich eine neue Zeichenfolge, dh ein neues Zeichenfolgenobjekt! StringBuilder erstellt jedoch eine veränderbare Zeichenfolge.


0

StringBuilder ist eine bessere Option, um eine große Datenzeichenfolge zu verknüpfen, da der StringBuilder ein veränderbarer Zeichenfolgentyp und das StringBuilder-Objekt ein unveränderlicher Typ ist. Dies bedeutet, dass StringBuilder niemals eine neue Objektinstanz erstellt, während die Zeichenfolge verknüpft wird.

Wenn wir String anstelle von StringBuilder verwenden, um eine Verkettung zu erzielen, wird jedes Mal eine neue Instanz im Speicher erstellt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.