c#中可变字符串和不可变字符串的区别是什么?

c#中可变字符串和不可变字符串的区别是什么?

239770 次浏览

String是不可变的

也就是说字符串不能被修改。当你改变一个字符串(例如通过添加),你实际上是在创建一个新的字符串。

但是StringBuilder不是不可变的(更确切地说,它是可变的)

所以如果你必须多次修改一个字符串,比如多次连接,那么使用StringBuilder

不变的:

当你对一个对象做一些操作时,它会创建一个新对象,因此state不能像string那样修改。

可变的

当您对对象执行某些操作时,对象本身不会像StringBuilder那样修改创建的新对象

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对象在c#中都是不可变的。类string的对象一旦创建,就不能表示除构造它们时使用的值以外的任何值。所有看似“改变”字符串的操作都会产生一个新的字符串。这对内存来说效率很低,但对于能够相信字符串不会改变它的形式非常有用——因为只要你不改变引用,被引用的字符串就永远不会改变。

相比之下,可变对象具有可以更改的数据字段。它的一个或多个方法将改变对象的内容,或者它有一个Property,当写入该Property时,将改变对象的值。

如果你有一个可变对象——与String最相似的对象是StringBuffer——那么你必须复制它,如果你想绝对确保它不会从你下面改变。这就是为什么使用可变对象作为任何形式的Dictionary或set的键是危险的——对象本身可能会改变,数据结构将无法知道,导致损坏的数据,最终导致程序崩溃。

然而,你可以改变它的内容-所以它比制作一个完整的副本要高效得多,因为你想改变一个字符或类似的东西。

一般来说,正确的做法是在创建东西时使用可变对象,完成后使用不可变对象。当然,这适用于具有不可变形式的对象;大多数的收藏都没有。不过,在将集合的内部状态发送到其他上下文中时,提供只读形式的集合通常是有用的,这相当于不可变的—否则,某些东西可能会获取该返回值,对其进行操作,并破坏数据。

一个对象是可变的,如果它一旦创建,它的状态可以通过调用对它的各种操作来改变,否则它是不可变的。

不可改变的字符串

在c#(和。net)中,字符串由类System.String表示。string关键字是这个类的别名。

系统。字符串类是不可变的,即一旦创建它的状态不能改变

因此,你对一个字符串执行的所有操作,如SubstringRemoveReplace,使用'+'操作符进行连接等,都会创建一个新字符串并返回它。

请参阅下面的程序进行演示

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

这将分别打印'string'和'mystring'。

对于不变性的好处和为什么字符串是不可变的,检查为什么。net字符串是不可变的?

可变的字符串

如果你想要一个经常修改的字符串,你可以使用StringBuilder类。__abc2 __abc0 __abc3。

有关何时使用 StringBuilder的更多建议,请参阅什么时候使用StringBuilder?

实现细节。

< p > CLR2的系统。字符串是可变的。 StringBuilder。追加调用字符串。AppendInplace (私有方法)< / p > < p > CLR4的系统。字符串是不可变的。

. StringBuilder有一个Char数组

澄清一下,在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();
在. net < p > 系统。String(又名String)是一个不可变对象。这意味着当你创建一个对象后,你不能改变它的值。只能重新创建不可变对象。< / p >

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";
它将在字符串池中寻找字符串“我爱的国家”,如果找到了,你将得到它的引用,其他明智的新字符串“我爱的国家”将在字符串池中创建,name2将得到它的引用。 但这整个过程“我的国家”没有改变,因为其他变量如的名字仍在使用它。 这就是为什么字符串是不可变的.

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框架中;换句话说,barbaz指向完全相同的字符串,因此改变其中一个会改变另一个。不过,如果你使用的是像WinRT这样的非托管平台,这一切都很好,因为它缺乏字符串实习。

c#中的字符串是不可变的。如果你将它与任何字符串连接,你实际上是在创建一个新字符串,这就是new string对象! 但是StringBuilder创建可变字符串

StringBuilder是连接大数据字符串的更好选择,因为StringBuilder是可变的字符串类型,而StringBuilder对象是不可变的类型,这意味着StringBuilder在连接字符串时永远不会创建一个新的对象实例。

如果我们使用string而不是StringBuilder来实现连接,那么它每次都会在内存中创建新的实例。