【问题标题】:Why isn't string concatenation automatically converted to StringBuilder in C#? [duplicate]为什么字符串连接不会在 C# 中自动转换为 StringBuilder? [复制]
【发布时间】:2012-02-25 19:24:03
【问题描述】:

可能重复:
Why is String.Concat not optimized to StringBuilder.Append?

有一天,我向我的一个朋友抱怨一个特定的 Telerik 控件。我告诉他生成控件树需要几秒钟,在分析后我发现它在循环中使用字符串连接而不是 StringBuilder。重写后它几乎立即生效。

所以我的朋友听说了,似乎很惊讶 C# 编译器没有像 Java 编译器那样自动进行转换。阅读了许多 Eric Lippert 的答案,我意识到这个功能没有成功,因为它被认为不够有价值。但是,如果假设实施它的成本很小,那么有什么理由会阻止人们这样做呢?

【问题讨论】:

  • 技术上没有什么可以阻止您执行此优化,但请考虑这两个操作在语义上并不等效。连接string 会返回一个新的string 对象,它是操作的结果,而使用StringBuilder 将修改现有的字符串对象。必须执行代码分析以确保您不会以任何方式依赖串联的副作用。在大多数情况下,这并不是一个无法克服的问题,但话说回来,一开始就正确编写代码并不是那么难。
  • 也看看这个帖子:pranayamr.blogspot.com/2011/02/…

标签: c# string stringbuilder compiler-optimization


【解决方案1】:

但是,如果假设实施它的成本很小,那么有什么理由会阻止人们这样做呢?

听起来你提出了一个重言式:如果没有理由不做 X,那么有理由不做 X 吗?没有。

我认为知道假设的、反事实问题的答案没有什么价值。也许更好的问题是关于现实世界的问题

是否有使用这种优化的编程语言?

是的。在 JScript.NET 中,我们检测循环中的字符串连接,编译器将它们转换为对字符串构建器的调用。

然后可能会跟进:

JScript .NET 和 C# 之间有哪些区别可以证明用一种语言进行优化而不用另一种语言进行优化?

JScript.NET 的一个核心假设是它的程序员主要是 JavaScript 程序员,其中许多人已经构建了必须在任何 ECMAScript 实现中运行的库。这些程序员可能不太了解 .NET 框架,即使他们了解,他们也可能无法使用 StringBuilder 而不使他们的库代码不可移植。还可以合理地假设 JavaScript 程序员可能是新手程序员,也可能是通过其业务线而不是计算机科学课程学习的程序员。

C# 程序员更有可能非常了解 .NET 框架,编写与该框架一起工作的库,并且成为理解为什么循环字符串连接为 O(n2) 的经验丰富的程序员在幼稚的实现中。他们不需要这种优化由编译器生成,因为如果他们认为有必要,他们可以自己做。

简而言之:编译器功能就是花费我们的预算为客户增加价值;与将功能添加到 C# 相比,将功能添加到 JScript.NET 可以获得更多的“物有所值”。

【讨论】:

  • 感谢您的回答。但是,我没有提出重言式。有时,出于意识形态原因而没有添加功能,而不仅仅是纯粹的成本(设计、实施、测试)。例如,您自己说过,C# 不包含 .ForEach 扩展名仅仅是因为它会引入不必要的歧义。添加这个 oneliner 的成本微乎其微,但基本原理与它们无关。但我认为你的最终结论是我与朋友一起使用的令人满意的论据。
  • @RomanR.:我对此表示怀疑。您能否举一个实际上并不构成基于成本的决策的意识形态决策的例子?
  • @Brian: RomanR 的例子很好;我们可以在IEnumerable<T> 上做一个 ForEach 扩展方法,成本很低,而且有一些好处,但在我看来,它不符合 LINQ 的“精神”,即避免副作用。那是“反对”做这个功能。当然也有反对这样做的预算论据,即不做更好的功能的机会成本。但是反对点就是反对点,并不是所有反对点都是基于成本的。
  • 个人不喜欢Foreach 扩展方法,原因与您类似。但是将它排除在框架之外的问题是,我们现在得到了许多微妙不同的第三方版本,因为很多人认为这是一个好主意。所以我认为目前的情况比将其包含在框架中更糟糕。
  • 看起来 Java 8 编译器确实执行了这种优化:dzone.com/articles/…
【解决方案2】:

C# 编译器比这更好。

a + b + c 被编译为String.Concat(a, b, c),这比StringBuilder更快
"a" + "b" 被直接编译为"ab"(对于多行文字很有用)。

唯一使用StringBuilder 的地方是在循环内重复连接时;编译器无法轻易优化它。

【讨论】:

  • 不管被连接的字符串的大小和数量,它真的更快吗?
  • 正是问题在说什么,不过:在循环中连接。
  • @CodyGray:我很难相信 Java 会优化它。
  • @Shredderroy:是的。 Concat 预先知道大小,所以它永远不需要重新分配。我不知道它与预置大小的StringBuilder 相比如何;我猜Concat 会快一点。
  • 编译器可以轻松优化它;这不是一个很难编写的优化。我们只是选择不这样做。
猜你喜欢
  • 2012-08-10
  • 2011-12-26
  • 2013-03-07
  • 1970-01-01
  • 2013-12-13
  • 1970-01-01
  • 1970-01-01
  • 2017-03-11
  • 1970-01-01
相关资源
最近更新 更多