Jaka jest różnica między ciągiem zmiennym i niezmiennym w języku C #?
Jaka jest różnica między ciągiem zmiennym i niezmiennym w języku C #?
Odpowiedzi:
Zmienne i niezmienne to angielskie słowa oznaczające odpowiednio „można zmienić” i „nie można zmienić”. Znaczenie słów jest takie samo w kontekście IT; to znaczy
Znaczenie tych słów jest takie samo w C # / .NET, jak w innych językach / środowiskach programowania, chociaż (oczywiście) nazwy typów mogą się różnić, podobnie jak inne szczegóły.
Dla przypomnienia:
String jest standardowym niezmiennym typem łańcucha C # / .Net StringBuilder jest standardowym typem ciągów zmiennych C # / .Net Aby „dokonać zmiany” na łańcuchu reprezentowanym jako C # String, faktycznie tworzysz nowy Stringobiekt. Oryginał Stringnie jest zmieniany ... ponieważ jest niezmienny.
W większości przypadków lepiej jest używać, Stringponieważ jest to łatwiejszy powód; np. nie musisz brać pod uwagę możliwości, że jakiś inny wątek może „zmienić mój ciąg”. Jednak gdy trzeba skonstruować lub zmodyfikować ciąg przy użyciu sekwencji operacji, bardziej efektywne może być użycie StringBuilder.
I wreszcie dla tych, którzy twierdzą, że: StringBuilder nie jest łańcuchem, ponieważ nie jest niezmienny, dokumentacja Microsoft opisuje w StringBuilderten sposób:
„Reprezentuje zmienny ciąg znaków. Nie można odziedziczyć tej klasy.”
String jest niezmienny
tzn. łańcuchy nie mogą być zmieniane. Kiedy zmieniasz ciąg (na przykład dodając do niego), w rzeczywistości tworzysz nowy ciąg.
Ale StringBuilder nie jest niezmienny (raczej jest zmienny)
więc jeśli musisz wiele razy zmieniać ciąg, na przykład wiele konkatenacji, użyj StringBuilder.
O(N^2)zachowania ...
Obiekt można modyfikować, jeśli po utworzeniu jego stan można zmienić, wywołując różne operacje na nim, w przeciwnym razie jest niezmienny.
W C # (i .NET) ciąg jest reprezentowany przez klasę System.String. Thestring kluczowe jest pseudonimem dla tej klasy.
Klasa system.string jest niezmienne, czyli po utworzeniu jego stan nie może być zmieniona .
Więc wszystkie operacje wykonać jak na sznurku Substring, Remove,Replace , za pomocą konkatenacji „+” operator itp stworzy nowy ciąg i zwraca go.
Zobacz następujący program demonstracyjny -
string str = "mystring";
string newString = str.Substring(2);
Console.WriteLine(newString);
Console.WriteLine(str);
Spowoduje to wydrukowanie odpowiednio „łańcucha” i „tajemnicy”.
Aby poznać zalety niezmienności i dlaczego ciąg jest niezmienny, sprawdź, dlaczego ciąg .NET jest niezmienny? .
Jeśli chcesz mieć ciąg, który chcesz często modyfikować, możesz użyć StringBuilderklasy. Operacje na StringBuilder instancji zmodyfikują ten sam obiekt .
Aby uzyskać więcej porad dotyczących tego, kiedy używać, StringBuilder zobacz Kiedy używać StringBuilder? .
Wszystkie stringobiekty są niezmienne w języku C #. stringPo utworzeniu obiekty klasy nigdy nie mogą reprezentować żadnej innej wartości niż ta, z którą zostały zbudowane. Wszystkie operacje, które wydają się „zmieniać” ciąg, zamiast tego tworzą nową. Jest to nieefektywne w przypadku pamięci, ale niezwykle przydatne w odniesieniu do zaufania, że ciąg znaków nie zmieni formy pod tobą - ponieważ dopóki nie zmienisz swojego odwołania, ciąg, do którego następuje odwołanie, nigdy się nie zmieni.
Natomiast obiekt zmienny ma pola danych, które można zmienić. Co najmniej jedna z jego metod zmieni zawartość obiektu lub ma właściwość, która po zapisaniu zmieni wartość obiektu.
Jeśli masz zmienny obiekt - najbardziej podobny do String StringBuffer- to musisz zrobić jego kopię, jeśli chcesz być absolutnie pewien, że nie zmieni się pod tobą. Dlatego zmienne obiekty są niebezpieczne jako klucze do dowolnej formyDictionary lub same obiekty mogą się zmienić, a struktura danych nie będzie mogła wiedzieć, co prowadzi do uszkodzenia danych, które ostatecznie spowodują awarię programu.
Możesz jednak zmienić jego zawartość - dzięki temu jest o wiele bardziej wydajna pamięć niż tworzenie pełnej kopii, ponieważ chciałeś zmienić pojedynczy znak lub coś podobnego.
Ogólnie rzecz biorąc, właściwą rzeczą do zrobienia jest używanie zmiennych obiektów podczas tworzenia czegoś, a niezmiennych obiektów po zakończeniu. Dotyczy to oczywiście obiektów, które mają niezmienne formy; większość kolekcji nie. Często przydatne jest jednak dostarczanie form kolekcji tylko do odczytu, co jest odpowiednikiem niezmienności, podczas wysyłania wewnętrznego stanu kolekcji do innych kontekstów - w przeciwnym razie coś może przyjąć tę wartość zwrotną, zrobić coś z nią i zepsuć dane.
Niezmienny:
Kiedy wykonujesz jakąś operację na obiekcie, tworzy on nowy obiekt, a zatem stanu nie można modyfikować, jak w przypadku łańcucha.
Zmienny
Kiedy wykonujesz jakąś operację na obiekcie, sam obiekt nie modyfikuje żadnego nowego obiektu, tak jak w przypadku StringBuilder
W .NET System.String (aka string) jest niezmiennym obiektem. Oznacza to, że podczas tworzenia obiektu nie można później zmienić jego wartości. Możesz odtworzyć tylko niezmienny obiekt.
System.Text.StringBuilder jest zmiennym odpowiednikiem System.String i można zmieniać jego wartość
Na przykład:
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");
}
}
Generuje następujący MSIL: Jeśli sprawdzasz kod. Zobaczysz, że za każdym razem, gdy wybierzesz obiekt System.String, faktycznie tworzysz nowy. Ale w System.Text.StringBuilder przy każdej zmianie wartości tekstu nie można odtworzyć obiektu.
.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
Ciągi można modyfikować, ponieważ .NET używa puli ciągów za sceną. To znaczy :
string name = "My Country";
string name2 = "My Country";
Zarówno nazwa, jak i nazwa2 odnoszą się do tej samej lokalizacji pamięci z puli ciągów. Załóżmy teraz, że chcesz zmienić name2 na:
name2 = "My Loving Country";
Przeszukuje pulę ciągów pod kątem ciągu „My Loving Country”, jeśli zostanie znaleziony, otrzymasz odniesienie do niego, inny mądry nowy ciąg „My Loving Country” zostanie utworzony w puli ciągów, a nazwa2 uzyska odniesienie do niego. Ale cały ten proces „ Mój kraj ” nie został zmieniony, ponieważ inna zmienna taka jak nazwa nadal go używa. I to jest powód, dla którego ciąg jest NIEZWYKLE .
StringBuilder działa w inny sposób i nie używa puli ciągów. Kiedy tworzymy dowolną instancję StringBuilder:
var address = new StringBuilder(500);
Przydziela fragment pamięci o wielkości 500 bajtów dla tej instancji, a wszystkie operacje po prostu modyfikują tę lokalizację pamięci i pamięć nie współdzieloną z żadnym innym obiektem. I to jest powód, dla którego StringBuilder jest MUTABLE .
Mam nadzieję, że to pomoże.
Właściwie nie. Klasa String jest zmienna.
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."
}
Tego rodzaju logika odbywa się cały czas w klasach String i StringBuilder. Po prostu przydzielają nowy ciąg za każdym razem, gdy wywołujesz Concat, Substring itp. I używają arytmetyki wskaźnika do kopiowania do nowego ciągu. Ciągi po prostu się nie mutują, dlatego są uważane za „niezmienne”.
Nawiasem mówiąc, nie próbuj tego z literałami łańcuchowymi, bo źle zepsujesz swój program:
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."
Wynika to z tego, że literały łańcuchowe są wbudowane w .NET Framework dla komputerów stacjonarnych; innymi słowy, bari bazwskaż dokładnie ten sam ciąg, więc mutacja jednego spowoduje mutację drugiego. To wszystko jest w porządku i eleganckie, jeśli używasz niezarządzanej platformy, takiej jak WinRT, której brakuje internowania ciągów.
Aby wyjaśnić, nie ma czegoś takiego jak zmienny ciąg w C # (lub .NET w ogóle). Inne języki obsługują zmienne ciągi (ciąg, który może się zmieniać), ale nie obsługuje środowiska .NET.
Tak więc poprawną odpowiedzią na twoje pytanie jest WSZYSTKIE ciągi znaków są niezmienne w języku C #.
ciąg ma określone znaczenie. Słowo kluczowe „string” to tylko skrót do obiektu utworzonego z klasy System.String. Wszystkie obiekty utworzone z klasy łańcuchów ZAWSZE są niezmienne.
Jeśli chcesz zmienną reprezentację tekstu, musisz użyć innej klasy, takiej jak StringBuilder. StringBuilder pozwala iteracyjnie budować kolekcję „słów”, a następnie konwertować ją na ciąg znaków (ponownie niezmienny).
StringBuilderzaprzecza temu: patrz msdn.microsoft.com/en-us/library/...
Wartości danych nie można zmienić. Uwaga: Wartość zmiennej można zmienić, ale pierwotna niezmienna wartość danych została odrzucona, a nowa wartość danych została utworzona w pamięci.
Z http://yassershaikh.com/what-is-the-difference-between-strings-and-stringbuilder-in-c-net/
Krótka odpowiedź: Ciąg jest niezmienny - podczas gdy StringBuilder jest zmienny.
Co to znaczy ? Wiki mówi: W obiektowym niezmiennym obiektem jest obiekt, którego stanu nie można zmienić po jego utworzeniu. Jest to przeciwieństwo obiektu zmiennego, który można modyfikować po jego utworzeniu.
Z dokumentacji klasy StringBuilder:
Obiekt String jest niezmienny. Za każdym razem, gdy użyjesz jednej z metod klasy System.String, tworzysz nowy obiekt łańcuchowy w pamięci, co wymaga nowego przydziału miejsca dla tego nowego obiektu.
W sytuacjach, w których trzeba wykonywać powtarzane modyfikacje łańcucha, narzut związany z tworzeniem nowego obiektu String może być kosztowny.
Klasy System.Text.StringBuilder można użyć, gdy chcesz zmodyfikować ciąg bez tworzenia nowego obiektu. Na przykład użycie klasy StringBuilder może zwiększyć wydajność podczas łączenia wielu łańcuchów w pętli.
Oto przykład Immutable string i Mutable string builder
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();
Ciąg w C # jest niezmienny. Jeśli połączysz go z dowolnym łańcuchem, tak naprawdę tworzysz nowy łańcuch, czyli nowy obiekt łańcucha! Ale StringBuilder tworzy zmienny ciąg.
StringBuilder to lepsza opcja konkatacji ogromnego ciągu danych, ponieważ StringBuilder jest zmiennym typem ciągu, a obiekt StringBuilder jest typem niezmiennym, co oznacza, że StringBuilder nigdy nie tworzy nowej instancji obiektu podczas konkatowania ciągu.
Jeśli używamy łańcucha zamiast StringBuilder do osiągnięcia konkatenacji, to za każdym razem utworzy nowe wystąpienie w pamięci.