c#中可变字符串和不可变字符串的区别是什么?
String是不可变的
String
也就是说字符串不能被修改。当你改变一个字符串(例如通过添加),你实际上是在创建一个新的字符串。
但是StringBuilder不是不可变的(更确切地说,它是可变的)
StringBuilder
所以如果你必须多次修改一个字符串,比如多次连接,那么使用StringBuilder。
不变的:
当你对一个对象做一些操作时,它会创建一个新对象,因此state不能像string那样修改。
可变的
当您对对象执行某些操作时,对象本身不会像StringBuilder那样修改创建的新对象
Mutable和immutable是英语单词,意思是“可以改变”。而“不能改变”;分别。在IT上下文中,单词的含义是相同的;即。
这些词在c# / . net中的含义与在其他编程语言/环境中的含义相同,尽管(显然)类型的名称可能不同,其他细节也可能不同。
郑重声明:
“造成改变”;在c# String表示的字符串上,实际上创建了一个新的String对象。原来的String没有改变…因为它是不可改变的。
在大多数情况下,最好使用String,因为它更容易解释它们;例如,你不需要考虑其他线程可能“改变我的字符串”的可能性。
然而,当你需要使用一系列操作来构造或修改字符串时,使用StringBuilder可能更有效。一个例子是当你连接许多字符串片段以形成一个大字符串:
O(N^2)
N
O(N)
最后,对于那些断言StringBuilder不是字符串的人,因为它不是不可变的,Microsoft 文档是这样描述StringBuilder的:
表示字符的可变的字符串。这个类不能被继承。
所有string对象在c#中都是不可变的。类string的对象一旦创建,就不能表示除构造它们时使用的值以外的任何值。所有看似“改变”字符串的操作都会产生一个新的字符串。这对内存来说效率很低,但对于能够相信字符串不会改变它的形式非常有用——因为只要你不改变引用,被引用的字符串就永远不会改变。
string
相比之下,可变对象具有可以更改的数据字段。它的一个或多个方法将改变对象的内容,或者它有一个Property,当写入该Property时,将改变对象的值。
如果你有一个可变对象——与String最相似的对象是StringBuffer——那么你必须复制它,如果你想绝对确保它不会从你下面改变。这就是为什么使用可变对象作为任何形式的Dictionary或set的键是危险的——对象本身可能会改变,数据结构将无法知道,导致损坏的数据,最终导致程序崩溃。
StringBuffer
Dictionary
然而,你可以改变它的内容-所以它比制作一个完整的副本要高效得多,因为你想改变一个字符或类似的东西。
一般来说,正确的做法是在创建东西时使用可变对象,完成后使用不可变对象。当然,这适用于具有不可变形式的对象;大多数的收藏都没有。不过,在将集合的内部状态发送到其他上下文中时,提供只读形式的集合通常是有用的,这相当于不可变的—否则,某些东西可能会获取该返回值,对其进行操作,并破坏数据。
一个对象是可变的,如果它一旦创建,它的状态可以通过调用对它的各种操作来改变,否则它是不可变的。
在c#(和。net)中,字符串由类System.String表示。string关键字是这个类的别名。
系统。字符串类是不可变的,即一旦创建它的状态不能改变。
因此,你对一个字符串执行的所有操作,如Substring, Remove, Replace,使用'+'操作符进行连接等,都会创建一个新字符串并返回它。
Substring
Remove
Replace
请参阅下面的程序进行演示
string str = "mystring"; string newString = str.Substring(2); Console.WriteLine(newString); Console.WriteLine(str);
这将分别打印'string'和'mystring'。
对于不变性的好处和为什么字符串是不可变的,检查为什么。net字符串是不可变的?。
如果你想要一个经常修改的字符串,你可以使用StringBuilder类。__abc2 __abc0 __abc3。
有关何时使用 StringBuilder的更多建议,请参阅什么时候使用StringBuilder?。
实现细节。
澄清一下,在c#(或一般的。net)中没有可变字符串这种东西。其他语言支持可变字符串(可以改变的字符串),但. net框架不支持。
所以你问题的正确答案是所有字符串在c#中都是不可变的。
字符串有特定的含义。"string"小写关键字仅仅是从System实例化的对象的快捷方式。String类。所有从string类创建的对象总是不可变的。
如果你想要一个可变的文本表示,那么你需要使用另一个类,比如StringBuilder。StringBuilder允许你迭代地构建一个“words”的集合,然后将其转换为字符串(同样是不可变的)。
从http://yassershaikh.com/what-is-the-difference-between-strings-and-stringbuilder-in-c-net/
简单回答:String是不可变的——而StringBuilder是可变的。
什么意思? Wiki说:在面向对象中,不可变对象是创建后状态不能修改的对象。这与可变对象相反,可变对象可以在创建后修改
来自StringBuilder类文档:
String对象是不可变的。每次使用系统中的一个方法时。String类,则在内存中创建一个新的字符串对象,这需要为该新对象分配新的空间。
在需要对字符串执行重复修改的情况下,与创建新string对象相关的开销可能很高。
当您希望修改字符串而不创建新对象时,可以使用System.Text.StringBuilder类。例如,在循环中将多个字符串连接在一起时,使用StringBuilder类可以提高性能。
数据值不可更改。注意:变量值可以改变,但原始的不可变数据值将被丢弃,并在内存中创建一个新的数据值。
下面是不可变字符串和可变字符串生成器的例子
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();
stringbuilder是System的可变等价。字符串,你可以改变它的值
例如:
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的对象时,您将看到这一点。字符串,你实际上是在创建一个新的。但是在System.Text.StringBuilder中,只要你改变了text的值,你就不会重新创建对象
.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
字符串是可变的,因为。net在后台使用字符串池。意思是:
string name = "My Country"; string name2 = "My Country";
name和name2都引用字符串池中相同的内存位置。 现在假设你想把name2改成
name2 = "My Loving Country";
StringBuilder以不同的方式工作,不使用字符串池。当我们创建StringBuilder的任意实例时:
var address = new StringBuilder(500);
它为这个实例分配大小为500字节的内存块,所有操作只是修改这个内存位置,并且这个内存不与任何其他对象共享。这就是为什么StringBuilder是可变的的原因。
我希望它能有所帮助。
实际上,没有一个。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框架中;换句话说,bar和baz指向完全相同的字符串,因此改变其中一个会改变另一个。不过,如果你使用的是像WinRT这样的非托管平台,这一切都很好,因为它缺乏字符串实习。
bar
baz
StringBuilder是连接大数据字符串的更好选择,因为StringBuilder是可变的字符串类型,而StringBuilder对象是不可变的类型,这意味着StringBuilder在连接字符串时永远不会创建一个新的对象实例。
如果我们使用string而不是StringBuilder来实现连接,那么它每次都会在内存中创建新的实例。