在C#中,可变字符串和不可变字符串有什么区别?
Mutable和immutable是英文单词,分别表示“可以更改”和“不可更改”。在IT上下文中,这些单词的含义相同:
这些单词在C#/.NET中的含义与其他编程语言/环境中的含义相同,尽管(显然)类型名称和其他细节可能不同。
记录一下:
String
是标准的C#/.Net不可变字符串类型StringBuilder
是标准的C#/.Net可变字符串类型要对表示为C# String
的字符串进行“更改”,实际上需要创建一个新的String
对象。原始的 String
没有被更改...因为它是不可更改的。
大多数情况下最好使用String
,因为它更易于理解;例如,您不需要考虑某些其他线程可能会“更改我的字符串”的可能性。
但是,当您需要使用一系列操作构建或修改字符串时,使用 StringBuilder
可能更有效率。例如,在将许多字符串片段连接成较大的字符串时:
String
,则会复制O(N ^ 2)
个字符,其中N
是组件字符串的数量。StringBuilder
,则只复制O(N)
个字符。最后,对于那些断言 StringBuilder
不是字符串因为它不可变的人,Microsoft 文档这样描述StringBuilder
:
"表示一个可变的字符字符串。此类不能被继承。"
String
是不可变的。
也就是说,字符串不能被改变。当你改变一个字符串(例如添加内容),实际上是创建了一个新的字符串。
但是 StringBuilder
是可变的。
因此,如果你需要多次修改一个字符串,比如多次拼接,那么请使用 StringBuilder
。
O(N^2)
的行为... - Stephen C如果一个对象被创建后可以通过调用各种操作来改变其状态,则该对象是可变的;否则它是不可变的。
在C#(和.NET)中,字符串由 System.String 类表示。string 关键字是此类的别名。
System.String 类是不可变的,即一旦创建其状态就不能更改。
因此,对字符串执行的所有操作(如 Substring、Remove、Replace、使用 '+' 操作符进行连接等)都会创建并返回一个新字符串。
请参见以下示例程序进行演示:
string str = "mystring";
string newString = str.Substring(2);
Console.WriteLine(newString);
Console.WriteLine(str);
这将分别打印'string'和'mystring'。
关于为什么字符串是不可变的以及不可变性的好处,请查看为什么.NET字符串是不可变的?。
如果您想要经常修改的字符串,可以使用StringBuilder
类。对StringBuilder
实例的操作将修改同一对象。
有关何时使用StringBuilder
的更多建议,请参见何时使用StringBuilder?。
string
类的对象,它们就不能表示除了构造时指定的值之外的任何值。所有看起来“更改”字符串的操作实际上都会生成一个新的字符串。这种方式虽然在使用内存方面效率较低,但是非常有用,因为只要不更改引用,被引用的字符串就永远不会改变。StringBuffer
-那么如果你想绝对确保它不会在你的控制下发生改变,你必须对其进行复制。这就是为什么可变对象在作为任何形式的Dictionary
或集合键时都是危险的原因-对象本身可能会发生变化,而数据结构无法知道,导致数据损坏,最终导致程序崩溃。Immutable:
当您对对象执行某些操作时,它会创建一个新对象,因此状态不可修改,就像字符串一样。
Mutable:
当您对对象执行某些操作时,对象本身被修改,而不是创建新的对象,就像StringBuilder一样。
在.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");
}
}
.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";
var address = new StringBuilder(500);
实际上没有。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 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."
bar
和baz
指向完全相同的字符串,所以改变一个将会改变另一个。然而,如果你正在使用像WinRT这样的非托管平台,它缺乏字符串内部化功能,这一点就不那么美好了。在实现细节方面。
CLR2的System.String是可变的。 StringBuilder.Append调用String.AppendInplace (私有方法)
CLR4的System.String是不可变的。 StringBuilder具有分块的Char数组。
澄清一下,在C#(或.NET框架)中,不存在可变字符串的概念。其他语言支持可变字符串(可以更改的字符串),但.NET框架不支持。
因此,对于您的问题,正确答案是C#中所有字符串都是不可变的。
字符串具有特定的含义。小写关键字"string"只是从System.String类实例化的对象的快捷方式。从string类创建的所有对象始终是不可变的。
如果您想要一个可变的文本表示,则需要使用另一个类,如StringBuilder。 StringBuilder允许您迭代地构建“单词”集合,然后将其转换为字符串(再次是不可变的)。
StringBuilder
的微软文档与此相矛盾:请参见https://msdn.microsoft.com/zh-cn/library/system.text.stringbuilder(v=vs.110).aspx。 - Stephen C