7

我们都知道串联字符串会导致效率问题,尤其是在循环中。我被教导使用StringBuilder来防止这些问题。

所以这:

str += someotherstring

变成这样:

StringBuilder sb = new StringBuilder();   
sb.AppendLine(someotherstring);

但据我了解,.NET 框架 3.5 及更高版本中的 CLR 足够智能,可以为两种方法输出相同的 IL。那么我是否有理由再在我的团队代码审查中强制执行 stringbuilder 了?

编辑:我认为Servy在评论中一针见血:

在连接编译时已知的多个字符串时就是这种情况。因此,在连接编译时已知的多个字符串时,无需使用 SB。在编译时连接多个未知字符串时,它不能这样做

4

4 回答 4

7

不,这并不总是正确的。如果你检查了这个如何提高 Visual C# 中的字符串连接性能,我不会

但是,.NET Framework 包含一个针对字符串连接进行了优化的 StringBuilder 类。它提供与在 C/C++ 中使用字符数组相同的好处,以及自动增加缓冲区大小(如果需要)并为您跟踪长度。本文中的示例应用程序演示了 StringBuilder 类的使用,并将性能与串联进行了比较。

当您在代码传递中执行多个循环或分叉时,最好使用 StringBuilder。

还要检查这个

StringBuilder 并不总是更快——第 1 部分,共 2 部分

这段代码在我的 PC 上运行了 1484 毫秒:

for (int i = 0; i <= 1000000; i++)  { 
    // Concat strings 3 times using StringBuilder 
    StringBuilder s = new StringBuilder(); 
    s.Append(i.ToString()); 
    s.Append(i.ToString()); 
    s.Append(i.ToString());  }

而这个,使用传统的连接,花费的时间略少(1344毫秒):

for (int i = 0; i <= 1000000; i++)  { 
    // Concat strings 3 times using traditional concatenation 
    string s = i.ToString(); 
    s = s + i.ToString(); 
    s = s + i.ToString();  }

上述数据表明,StringBuilder 仅在连接数超过 3 时才开始更快地工作。

蒂姆发表的评论中有很好的链接,其中提到了

经验法则

那么,什么时候应该使用StringBuilder,什么时候应该使用字符串连接运算符呢?

  • 当您在一个重要的循环中连接时,绝对使用 StringBuilder - 特别是如果您不确定(在编译时)您将通过循环进行多少次迭代。例如,一次读取文件一个字符,使用 += 运算符构建一个字符串可能会导致性能自杀。
  • 当您可以(可读)指定需要在一个语句中连接的所有内容时,请务必使用连接运算符。(如果您有一系列要连接的东西,请考虑显式调用 String.Concat - 或 String.Join 如果您需要分隔符。)
  • 不要害怕将文字分成几个连接的位 - 结果是一样的。例如,您可以通过将长文字分成几行来提高可读性,而不会损害性能。
  • 如果您需要连接的中间结果而不是提供下一次连接迭代,StringBuilder 不会帮助您。例如,如果您从名字和姓氏构建一个全名,然后在末尾添加第三条信息(可能是昵称),那么只有在您不这样做的情况下,您才会从使用 StringBuilder 中受益需要 (first name + last name) 字符串用于其他目的(就像我们在创建 Person 对象的示例中所做的那样)。
  • 如果您只需要进行一些串联,并且您真的想在单独的语句中执行它们,那么您走哪条路并不重要。哪种方式更有效将取决于所涉及的字符串大小的连接数量以及它们连接的顺序。如果您真的认为那段代码是性能瓶颈,请以两种方式对其进行分析或基准测试。
于 2013-10-25T15:13:21.177 回答
2

但据我了解,.NET 框架 3.5 及更高版本中的 CLR 足够智能,可以为两种方法输出相同的 IL。

,这没有必要。您不能依靠编译器在循环中对其进行优化。它也更好用,StringBuilder因为它在字符串连接方面肯定会更好,并提供更好的可读性。

于 2013-10-25T15:11:45.690 回答
0

.NET 中的字符串是不可变的。一旦构建,它们就不能在以后修改。如果你想修改一个字符串,你需要从旧的创建一个新的并扔掉旧的。

另一方面,可以将 StringBuilder 视为可变字符串。在构造它之后改变它的内容是可能的,并且不需要分配一个全新的对象。

在比较使用 StringBuilder 和字符串连接执行类似操作所花费的时间时,通常不会出现不同的性能特征。效果更间接:虽然字符串连接可能会产生大量短暂的临时对象,但 StringBuilder 不会。因此,使用 StringBuilder 可以显着降低托管堆上的内存压力,从而减少代价高昂的垃圾回收的必要性。

但这一切都取决于您的应用程序,我不会尝试提供任何通用建议。执行大量字符串操作的应用程序(如 Web 服务器)比不执行的应用程序需要更多关注。如果您了解字符串和 StringBuilder 的不同之处及其含义,您应该能够做出明智的决定。如果有疑问:个人资料。但一定要分析 GC 周期。

于 2013-10-25T18:09:18.703 回答
0

StringBuilder例如,当您连接任意数量的字符串值时将使用。如果这个场景听起来像你的场景,那么,是的,你应该强制使用StringBuilder.

于 2013-10-25T15:12:29.863 回答