如何明智地使用StringBuilder?

时间:2014-02-08 10:07:46

标签: c# .net string memory stringbuilder

我对使用StringBuilder类感到困惑,首先:

  

string对象并置操作始终从现有string和新数据创建新对象。 StringBuilder对象维护缓冲区以容纳新数据的连接。如果房间可用,新数据将附加到缓冲区的末尾;否则,分配一个新的,更大的缓冲区,将原始缓冲区中的数据复制到新缓冲区,然后将新数据附加到新缓冲区。

但创建StringBuilder实例以避免创建String的新实例的重点是什么?这听起来像是“一对一”交易。

static void Main(string[] args)
{
    String foo = "123";
    using (StringBuilder sb = new StringBuilder(foo)) // also sb isn't disposable, so there will be error
    {
        sb.Append("456");
        foo = sb.ToString();
    }

    Console.WriteLine(foo);
    Console.ReadKey();
}

为什么我不应该只使用

+=

编辑: 好的,我现在知道如何重用StringBuilder的一个实例(仍然不知道这是否符合代码标准),但这只是一个string不值得使用,不是吗?

3 个答案:

答案 0 :(得分:97)

修改 immutable 结构(如string)必须通过复制结构来完成,并且由此消耗更多内存并减慢应用程序的运行时间(同时增加{{} 1}}时间等...)。

GC通过使用相同的可变对象进行操作来解决这个问题。

<强> 然而:

在编译时将StringBuilder连接起来如下:

string

它实际上会编译成类似的东西:

string myString = "123";
myString += "234";
myString += "345";

此功能比使用string myString = string.Concat("123", "234", "345"); 更快,因为已知进入该功能的StringBuilder个数。

因此,对于编译时已知的string个连接,您应该更喜欢string

对于未知数量的string.Concat(),如下例所示:

string

现在编译器不能使用string myString = "123"; if (Console.ReadLine() == "a") { myString += "234"; } myString += "345"; 函数,但是,string.Concat()仅在连接完成时使用6-7或更多{{1}时,在时间和内存消耗方面似乎更有效}}

不良做法:

StringBuilder

精细练习用法(注意使用strings):

StringBuilder myString = new StringBuilder("123");
myString.Append("234");
myString.Append("345");

最佳实践用法(请注意,使用了if循环):

StringBuilder myString = new StringBuilder("123");
if (Console.ReadLine() == "a")
{
    myString.Append("234");
}
myString.Append("345");

答案 1 :(得分:12)

string不可变类。您无法修改它,只能创建新的strings

因此,当您撰写result += a;时,内存中有三个单独的stringsa,旧值result和新值。当然,如果你只连接有限数量的strings,这绝对没问题。如果你在迭代大型集合的for循环中执行此操作,则可能会出现问题。

StringBuilder类在这些情况下提供了改进的性能。而不是创建新的strings来存储连接的结果,它使用相同的对象。因此,如果您使用stringBuilder.Append(a);,则永远不会具有“result的旧值”。


这种内存效率当然需要付出代价。当只连接少量strings StringBuilder时,速度通常效率较低,因为与不可变string类相比,它具有更多的开销。


要记住的一件事是,当您需要中间字符串时,StringBuilder可能效率降低,因为在其上调用.ToString()会创建string的新副本。

答案 2 :(得分:1)

原因是因为strings是不可变的。连接string时,您会创建一个新的string。因此,当您需要连接多个strings时,您会创建大量objects。这在内存方面不会花费太多,因为每个string使用一次。但它确实为GC提供了额外的工作。

然而,

StringBuilder每次都使用相同的object,但这样做会牺牲易用性。