C#中的可变和不可变string有什么区别?

C#中的可变和不可变string有什么区别?

可变和不可变的英文单词分别表示“可以改变”和“不能改变”。 这个词的意思在IT环境中是一样的; 即

  • 一个可变的string可以被改变,并且
  • 一个不可变的string不能被改变。

这些词的含义在C#/ .NET中与其他编程语言/环境中的相同,不过(显然)这些types的名称可能不同,其他细节也可能不同。


作为logging:

  • String是标准的C#/ .Net不可变stringtypes
  • StringBuilder是标准的C#/ .Net可变stringtypes

为了对以C# String表示的string进行“改变”,你实际上创build了一个新的String对象。 原来的String没有改变…因为它是不可改变的。

在大多数情况下,最好是使用String因为它更容易理解; 例如,你不需要考虑其他线程可能会“改变我的string”的可能性。 但是,当您需要使用一系列操作构造或修改string时,使用StringBuilder可能更有效。

String是不可变的

即string不能被改变。 当你改变一个string(例如通过添加),你实际上正在创build一个新的string。

但是StringBuilder不是不可变的(而是可变的)

所以如果你必须多次改变一个string,比如多个连接,那么就使用StringBuilder

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

不可变的string

在C#(和.NET)中,一个string由类System.String表示。 string关键字是这个类别的别名。

System.String类是不可变的,即一旦创build它的状态不能改变

因此,对string执行的所有操作(如“子串”,“移除”,“replace”,使用“+”运算符等连接)将创build一个新string并将其返回。

请参阅以下程序进行演示 –

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

这将分别打印“string”和“mystring”。

为了不变性好处,以及为什么string是不可变的检查为什么.NETstring是不可变的? 。

可变的string

如果你想要一个你想经常修改的string,你可以使用StringBuilder类。 StringBuilder 实例的 操作 将修改同一个对象

有关何时使用 StringBuilder更多build议请参阅何时使用StringBuilder? 。

所有string对象在C#中是不可变的。 类string对象一旦创build,就永远不能表示除了它们所构build的值以外的任何值。 所有似乎“改变”一个string的操作都会产生一个新的操作。 这对于内存来说是低效的,但对于能够相信一个string不会改变你的forms是非常有用的 – 因为只要你不改变你的引用,被引用的string将永远不会改变。

相反,可变对象具有可以改变的数据字段。 它的一个或多个方法将会改变对象的内容,或者它有一个属性,在写入的时候会改变对象的值。

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

然而,你可以改变它的内容,所以比制作一个完整的副本更有效率,因为你想改变一个单独的字符或类似的东西。

一般来说,正确的做法是在创build内容时使用可变对象,在完成后使用不可变对象。 这当然适用于具有不变forms的对象。 大部分collections品都没有。 向集合的内部状态发送其他上下文时,提供只读forms的集合通常是非常有用的,否则,某些东西可能会带来返回值,对它做些什么,并破坏你的数据。

不可变的:

当你在一个对象上进行一些操作时,它会创build一个新的对象,因此状态不能像string一样修改。

易变的

当你在一个对象上执行一些操作时,对象本身并没有像在StringBuilder的情况下那样修改创build的新对象

在.NET System.String(又名string)是一个不可变的对象。 这意味着当你创build一个对象后,你不能改变它的值。 你只能重新创build一个不可变的对象。

System.Text.StringBuilder是可变等价的System.String,你可以chane它的值

例如:

 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:如果您调查的代码。 你会看到,每当你chane一个System.String的对象,你实际上正在创造一个新的。 但是在System.Text.StringBuilder中,每当你改变文本的值,你都不会重新创build对象。

 .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 

string是可变的,因为.NET使用场景后面的string池。 它的意思是 :

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

名称和名称2都是指string池中相同的内存位置。 现在假设你想把name2改成:

 name2 = "My Loving Country"; 

它会查找string池中的string“我爱你的国家”,如果发现你会得到它的引用其他明智的新string“我的爱国”将在string池中创build和名称2将得到它的参考。 但是这整个过程“ 我的国家 ”并没有改变,因为像名字这样的其他variables仍在使用它。 这就是为什么string是IMMUTABLE的原因。

StringBuilder以不同的方式工作,不使用string池。 当我们创buildStringBuilder的任何实例时:

 var address = new StringBuilder(500); 

它为这个实例分配大小为500字节的内存块,所有的操作只是修改这个内存位置,这个内存不与任何其他对象共享。 这就是为什么StringBuilderMUTABLE的原因。

我希望这会有所帮助。

没有,实际上。 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,并使用指针算术复制到新的string。 string不会改变自己,因此它们被认为是“不变的”。


顺便说一下,不要试图用string文字,否则你会搞砸你的程序:

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

这是因为string文字是在桌面.NET Framework中执行的; 换句话说, barbaz指向完全相同的string,所以变异会使另一个变异。 虽然如果你使用WinRT这样的非托pipe平台,但是没有string实习,这一切都很好。

澄清在C#(或一般的.NET)中不存在可变string。 其他语言支持可变string(可以改变的string),但.NET框架不支持。

所以你的问题的正确答案是所有string在C#中是不可变的。

string具有特定的含义。 “string”小写关键字仅仅是一个从System.String类实例化的对象的快捷方式。 从string类创build的所有对象总是不可变的。

如果你想要一个可变的文本表示,那么你需要使用另一个像StringBuilder这样的类。 StringBuilder允许您迭代地构build“单词”集合,然后将其转换为string(再次不可变)。

在实施细节。

CLR2的System.String是可变的。 StringBuilder.Append调用String.AppendInplace(私有方法)

CLR4的System.String是可以被修改的。 StringBuilder具有分块的Char数组。

数据值可能不会改变。 注意:variables值可能会改变,但原始的不可变数据值被丢弃,并在内存中创build一个新的数据值。

string是不可变的,这意味着我们每次都在分配新的内存,而不是在现有的string上工作。

string在池中创build。 如果一个string已经存在,它根本不会创build它。

 for (int i = 0; i < 1000; i++) { str += "Modified "; } 

StringBuilder是一个可变types,这意味着我们正在使用相同的内存位置,并继续追加/修改的东西到一个实例。 它不会创build任何进一步的实例,因此不会降低应用程序的性能。

 for (int i = 0; i < 10000; i++) { strB.Append("Modified "); } 

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

简答:string是不可变的,而StringBuilder是可变的。

那是什么意思 ? Wiki说:在面向对象中,不可变的对象是一个对象,它的状态在创build后不能被修改。 这与可变对象相反,可以在创build后对其进行修改。

从StringBuilder类文档:

String对象是不可变的。 每次使用System.String类中的某个方法时,都会在内存中创build一个新的string对象,这需要为该新对象重新分配空间。

在需要对string进行重复修改的情况下,与创build新的String对象相关的开销可能会很高。

当你想修改一个string而不创build一个新的对象时,可以使用System.Text.StringBuilder类。 例如,使用StringBuilder类可以在循环中将许多string连接在一起时提升性能。

这里是不可变string和可变string生成器的例子

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

C#中的string是不可变的。 如果你把它与任何string连接起来,你实际上正在创build一个新的string,那就是新的string对象! 但StringBuilder创build可变的string。