什么是InplaceStringBuilder和StringBuilder之间的区别?

时间:2017-03-22 18:58:48

标签: memory-management asp.net-core .net-core stringbuilder

当我尝试输入InplaceStringBuilder时,今天在VS2017中,intellisense浮出水面StringBuilderInplaceStringBuilder对我来说是新的,所以我开始挖掘,看看我能学到什么。

我注意到的第一件事是它是一个结构而不是一个类,它的类型信息如下所示:

#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少。然后我用Google搜索了解有关InplaceStringBuilder的更多信息,但网上关于它的内容并不多,所以它看起来很新。

此外,我已经提到的差异,InplaceStringBuilderStringBuilder之间有什么区别;什么时候开发人员应该使用新的InplaceStringBuilder而不是年龄StringBuilder

3 个答案:

答案 0 :(得分:4)

由于它只进行一次分配,InplaceStringBuilder对于众所周知的,合理大小的字符串更有效。我们可能希望在需要非常高效的方法中使用它。

引入了pull request #157,其中包括以下评论。

  

当字符串的所有部分都已知时,打算用来代替池StringBuilderstring.Concat ...只有1个分配的结果字符串......应该只用于众所周知的大小的字符串对于其他所有内容,请使用StringBuilder ...不要在等待点之间使用...

PR的历史讲述了这个故事:

  1. 2016年7月,Issue #676注意到不必要的分配。
  2. 2016年9月,Pull request #699解决了问题#676并提议将" inplace字符串格式分解为结构..."
  3. 2016年9月,Issue #717正式确定了提案。
  4. 2016年9月,Pull request #157实施了提案。

答案 1 :(得分:3)

当结果字符串长于初始容量时,正常StringBuilder会增加容量。 InplaceStringBuilder仅限于其容量,如果结果字符串较长,则抛出异常。

这是InplaceStringBuilder的一个限制,因此它可能仅适用于极少数情况。此外,如果您事先知道容量,则已经可以定义正常StringBuilder的初始容量。

来源:查看GitHubInplaceStringBuilder的实施情况,并与MSDN上的StringBuilder进行比较

答案 2 :(得分:3)

InplaceStringBuilder是通过附加块来构建字符串的非常快速的方法,当您事先知道最终字符串将要持续多长时间时。它的工作方式是预先分配一个固定大小的string,然后在将块追加到生成器时(不安全地通过指针)对该字符串进行变异。当您调用ToString时,将立即返回已充满数据的预分配字符串,而不进行复制。 (StringBuilder会在您调用ToString时复制其内容。)

字符串通常是不可变的,因此最好在调用Append之后通过调用ToString来确保不对字符串进行突变。 InplaceStringBuilder试图通过仅允许附加(您不能倒退并写入已经附加的字符串的一部分)并要求您在调用ToString之前填充整个字符串来确保此安全

但是,InplaceStringBuilder是可变的结构,这意味着它是通过复制传递的。如果您复制构建器(例如,通过将其作为参数传递),则该副本可能与原始文件不同步。具体而言,副本的_offset字段可跟踪字符串中到目前为止的位置(以便知道在何处写入下一个Append调用),该副本可引用字符串中的某个位置,已经是原著写的了。

这就是说InplaceStringBuilder不安全且有使用风险。如果处理不当,可能会破坏string最重要的属性之一,即不变性。确保您知道自己在做什么!