StringBuilder如何在C#内部工作?

时间:2011-06-29 16:44:19

标签: c# .net string stringbuilder

StringBuilder如何运作?

内部做什么?它使用不安全的代码吗? 为什么它如此之快(与+运算符相比)?

4 个答案:

答案 0 :(得分:66)

使用+运算符构建字符串时:

string s = "01";
s += "02";
s += "03";
s += "04";

然后在第一个连接中我们创建一个长度为4的新字符串并将“01”和“02”复制到其中 - 复制了四个字符。在第二个连接中,我们创建一个长度为6的新字符串并将“0102”和“03”复制到其中 - 复制了六个字符。在第三个concat上,我们创建一个长度为8的字符串并将“010203”和“04”复制到其中 - 复制了8个字符。到目前为止,这个8个字符的字符串总共复制了4 + 6 + 8 = 18个字符。继续。

...
s += "99";

在第98次结束时,我们制作一个长度为198的字符串,并将“010203 ... 98”和“99”复制到其中。这给了我们总共4 + 6 + 8 + ... + 198 =很多,为了使这个198字符串。

字符串构建器不能完成所有复制。相反,它维护一个希望比最终字符串更大的可变数组,并根据需要将新内容填充到数组中。

当猜测错误且阵列变满时会发生什么?有两种策略。在以前版本的框架中,字符串构建器在数组填满时重新分配并复制了数组,并将其大小加倍。在新实现中,字符串构建器维护一个相对较小的数组的链接列表,并在旧的数组变满时将新数组附加到列表的末尾。

此外,正如您猜测的那样,字符串构建器可以使用“不安全”代码来提高其性能。例如,将新数据写入数组的代码已经检查过数组写入是否在边界内。通过关闭安全系统,它可以避免每次写入检查抖动可能会插入以验证每次写入阵列是否安全。字符串生成器执行许多这样的操作来执行诸如确保重用缓冲区而不是重新分配缓冲区,确保避免不必要的安全检查等等。除非你真的擅长正确编写不安全的代码,否则我建议不要使用这些恶作剧,而且确实需要摒弃每一个性能。

答案 1 :(得分:15)

我相信,

StringBuilder的版本之间的实现已经发生了变化。从根本上说,它保持了某种形式的可变结构。我相信使用来使用一个仍在变异的字符串(使用内部方法),并确保它在返回后永远不会发生变异。

StringBuilder比在循环中使用字符串连接更快的原因正是由于可变性 - 它不需要在每次突变后构造新的字符串,这将意味着复制字符串中的所有数据等。

对于单个串联,使用+比使用StringBuilder效率更高一些。只有在您执行多个操作时,您才真正需要StringBuilder闪耀的中间结果。

有关详细信息,请参阅my article on StringBuilder

答案 2 :(得分:3)

Microsoft CLR使用内部调用执行某些操作(与不安全代码不完全相同)。与一堆+串联字符串相比,最大的性能优势是它写入char[]并且不会创建任意数量的中间字符串。当您调用ToString()时,它会根据您的内容构建一个完整的,不可变的字符串。

答案 3 :(得分:1)

StringBuilder使用可以更改的字符串缓冲区,而不是常规String。当你调用ToString的{​​{1}}方法时,它只会冻结字符串缓冲区并将其转换为常规字符串,因此不必再多次复制所有数据。

由于StringBuilder可以更改字符串缓冲区,因此不必为字符串数据的每次更改创建新的字符串值。当您使用StringBuilder运算符时,编译器会将其转换为创建新字符串对象的+调用。这段看似无辜的代码:

String.Concat

编译成:

str += ",";