InplaceStringBuilder和StringBuilder有什么区别?

6
今天在VS2017中,当我试图输入StringBuilder时,智能感知出现了InplaceStringBuilder。InplaceStringBuilder对我来说是新的,所以我开始挖掘看看能学到什么。
我注意到的第一件事是它是一个结构体而不是类,并且它的类型信息如下:
#region Assembly Microsoft.Extensions.Primitives, Version=1.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// C:\Users\Ron Clabo\Documents\Visual Studio 2017\Projects\wwwGiftOasisResponsive\packages\Microsoft.Extensions.Primitives.1.1.0\lib\netstandard1.0\Microsoft.Extensions.Primitives.dll
#endregion

using System.Diagnostics;

namespace Microsoft.Extensions.Primitives {
    [DebuggerDisplay("Value = {_value}")]
    public struct InplaceStringBuilder {
        public InplaceStringBuilder(int capacity);

        public int Capacity { get; set; }

        public void Append(string s);
        public void Append(char c);
        public override string ToString();
    }
}

因此,它的方法比StringBuilder少得多。然后我在谷歌上搜索了解更多关于InplaceStringBuilder的信息,但是网上没有太多关于它的内容,所以它似乎相当新。
除了我已经提到的区别外,InplaceStringBuilder和StringBuilder之间还有哪些区别?开发人员什么时候应该使用新的InplaceStringBuilder而不是老旧的StringBuilder呢?

除了 旨在在所有字符串部分已知时替代池化 StringBuilder 或 string.Concat 使用 之外,似乎没有太多关于它的信息。 - DavidG
3个回答

5
由于它只分配一次内存,InplaceStringBuilder 对于已知、大小适中的字符串更加高效。我们可能想在需要非常高效的方法中使用它。
它是通过 pull request #157 引入的,该请求包括以下评论。

旨在替代池化的 StringBuilderstring.Concat,当字符串的所有部分都已知时使用... 仅对生成的字符串进行一次分配... 只应用于已知且大小适中的字符串。对于其他情况,请使用 StringBuilder... 不要跨越等待点使用...

PR 的历史记录讲述了这个故事:
  1. 2016 年 7 月,Issue #676 发现了不必要的内存分配。
  2. 2016 年 9 月,Pull request #699 解决了问题 #676,并提出了将“原地字符串格式化”分解为一个结构体的方案...
  3. 2016 年 9 月,Issue #717 正式提出了该方案。
  4. 2016 年 9 月,Pull request #157 实现了该方案。

3
InplaceStringBuilder是一种非常快速的构建字符串的方式,它通过追加块来构建字符串,当您预先知道最终字符串的长度时。它通过预先分配固定大小的string,并将该字符串(通过指针不安全地)随着向构建器追加块而“变异”。当您调用ToString时,现在充满数据的预分配字符串将直接返回,而无需复制。(当您调用ToString时,StringBuilder会复制其内容。)
字符串通常是不可变的,因此在调用ToString之后通过调用Append来改变字符串时,请确保不进行更改。InplaceStringBuilder尝试通过仅允许附加(您不能倒回并写入已经附加的字符串的部分)并要求在调用ToString之前填充整个字符串来使此过程安全。
然而,InplaceStringBuilder是一个可变的结构体,这意味着它是通过复制传递的。如果您复制了构建器(例如通过将其作为参数传递),则副本可能会与原始版本失去同步。具体而言,副本的_offset字段(用于跟踪追加了多少字符,以便知道下一个Append调用的写入位置)可能会引用已由原始字符串编写的位置。
这就是说,InplaceStringBuilder不安全且使用起来具有风险的。如果不小心处理,您可能会破坏string最重要的属性之一:不可变性。请确保知道自己在做什么!

3
普通的StringBuilder在结果字符串长度超过初始容量时会增加容量。而InplaceStringBuilder则限制于其容量,如果结果字符串更长,则会抛出异常。
这是InplaceStringBuilder的一个相当大的限制,因此它可能只适用于极少数情况。此外,如果您事先知道容量,那么已经可以定义普通的StringBuilder的初始容量。
来源:请查看GitHub上的InplaceStringBuilder实现,并将其与MSDN上的StringBuilder进行比较。

你有这个来源吗? - DavidG
那只是源代码的链接,我的意思是,你有没有一个官方人员重申你所说的话的文档或链接。 - DavidG
非常有趣。同意已经可以定义普通 StringBuilder 的初始容量,这将消除多次分配的需要。 - RonC
@ThomasWeller 不用担心,当我写问题时,我一直打错了不同的变体名称。InplaceStringBuilder需要一点时间才能记住。实际上,在查看源代码后,更好的名称可能是InplaceStringManipulator :-) - RonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接