StringBuilder如何在C#内部工作?

Alo*_*kin 45 .net c# string stringbuilder

StringBuilder工作怎么样?

内部有什么作用?它使用不安全的代码吗?为什么它如此之快(与+运营商相比)?

Eri*_*ert 68

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

string s = "01";
s += "02";
s += "03";
s += "04";
Run Code Online (Sandbox Code Playgroud)

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

...
s += "99";
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • 可能值得添加一个注释,如果你做了字符串s = x + y + z,那就不会发生这种情况; (使用String.Concat)以防任何愚蠢的人决定他们需要将所有这些"优化"为StringBuilders(严重的是我知道那些人这样做了) (3认同)
  • 我不知道关于StringBuilder的新版本 - 这是一个很好的优化.如果我将大量字符串附加到字符串构建器,它是否使用您为新创建的数组提到​​的"相对较小"的数组大小,还是使用更大的大小来适应我的整个新字符串? (2认同)
  • 如果您做了`string s =“ 01” +“ 02” +“ 03” +“ 04”`,它将被编译成`string s = string.Concat(“ 01”,“ 02”,“ 03”,“ 04” )`?(实际上,我认为编译器只会将其优化为`string s =“ 01020304”`,但如果所有部分都不是硬编码的字符串值,它将使用String.Concat吗?) (2认同)
  • @Nick:是的.对Concat的每个*call*获取其所有参数的*total*长度,并分配一个足够大的新字符串. (2认同)

Jon*_*eet 17

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

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

对于单个连接,使用它实际上+比使用更有效StringBuilder.只有在你进行多项操作时,你才真正需要中间结果才能StringBuilder发光.

有关更多信息,请参阅我的文章StringBuilder.