一尘不染

C#中的string和StringBuilder之间的区别

c#

string和之间有什么区别StringBuilder

另外,有什么例子可以理解?


阅读 329

收藏
2020-05-19

共1个答案

一尘不染

一个string实例是不可变的。创建后便无法更改。似乎更改字符串的任何操作都将返回一个新实例:

string foo = "Foo";
// returns a new string instance instead of changing the old one
string bar = foo.Replace('o', 'a');
string baz = foo + "bar"; // ditto here

不可变对象具有一些不错的属性,例如可以在线程中使用它们而不必担心同步问题,或者您可以直接直接分发私有支持字段,而不必担心有人更改了不应更改的对象(请参见数组或可变列表,如果不需要的话,通常需要在返回之前将其复制)。但是,如果不小心使用它们,可能会导致严重的性能问题(几乎所有问题–如果您需要一个以执行速度而自豪的语言为例,请查看C的字符串操作函数)。

当您需要一个 可变的 字符串(例如您要分段构造的字符串或要在其中进行很多更改的字符串)时,您将需要一个StringBuilder,它是 可以
更改的字符缓冲区。在大多数情况下,这会影响性能。如果您想要一个可变的字符串,而不是对一个普通的string实例进行处理,那么最终将不必要地创建和销毁许多对象,而StringBuilder实例本身将发生变化,从而消除了对许多新对象的需求。

简单的示例:以下内容将使许多程序员感到痛苦:

string s = string.Empty;
for (i = 0; i < 1000; i++) {
  s += i.ToString() + " ";
}

您最终将在此处创建2001个字符串,其中的2000个将被丢弃。使用StringBuilder的相同示例:

StringBuilder sb = new StringBuilder();
for (i = 0; i < 1000; i++) {
  sb.Append(i);
  sb.Append(' ');
}

这样可以减轻内存分配器的压力:-)

但是,应注意的是,对于字符串,C#编译器相当聪明。例如,以下行

string foo = "abc" + "def" + "efg" + "hij";

将由编译器加入,在运行时仅保留一个字符串。类似地,诸如

string foo = a + b + c + d + e + f;

将被重写为

string foo = string.Concat(a, b, c, d, e, f);

因此您不必为五个无意义的连接付费,这将是处理该连接的幼稚方式。这不会像上面那样在循环中节省您的时间(除非编译器展开循环,但我认为只有JIT可以这样做,并且最好不要打赌)。

2020-05-19