如何明智地使用StringBuilder?


72

首先,我对使用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,不是吗?



1
@royB“字符串争用本地使用stringbuilder(str1 + str2)”是什么意思?实际上,字符串连接在内部使用StringBuilder。
Lasse V. Karlsen 2014年

Answers:


110

修改s之类的不可变结构string必须通过复制结构来完成,这样会占用更多内存并减慢应用程序的运行时间(还会增加GC时间,等等)。

StringBuilder 通过使用相同的可变对象进行操纵来解决此问题。

然而:

string在编译时按以下方式串联时:

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

它实际上会编译成这样的东西:

string myString = string.Concat("123", "234", "345");

StringBuilder对于string已知进入该函数的s数量,此函数比使用它要快。

因此,对于编译时已知的string串联,您应该首选string.Concat()

至于string在以下情况下的未知数目:

string myString = "123";
if (Console.ReadLine() == "a")
{
    myString += "234";
}
myString += "345";

现在,编译器无法使用该string.Concat()函数,但是,StringBuilder仅当使用6-7或更高的级数进行串联时,它似乎才在时间和内存消耗上更加高效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");

最佳实践用法(请注意使用while循环):

StringBuilder myString = new StringBuilder("123");
while (Console.ReadLine() == "a")
{
    myString.Append("234"); //Average loop times 4~ or more
}
myString.Append("345");

您的最后两个示例不是完全一样吗?
Jaimie Knox

2
@JaimieKnox注意while/if和注释。
Tamir Vered

3
谢谢你 我一定已经读了100遍了,但仍然错过了。
Jaimie Knox

如果您要for循环连接列表中的每个项目怎么办?将+=编译为:string.concatenate(a,b,...,z)?如果是这样,StringBuilder如果列表中有〜4个或更多项目,您是否使用a ?
怪物

1
@monster由于编译器无法假定in中的任何内容,因此不会一次编译到string.Concat(中的所有stringsin之间List),因此,如果您假设会有多个串联-应该使用。stringsListStringBuilder
塔米尔·韦里德

13

Astring是一个不变的类。您不能修改它,只能创建new strings

因此,在编写时,此时内存中result += a;有三个单独的strings位置:a,的旧值result和新的值。当然,如果只连接有限数量的,这绝对没问题strings。如果以for循环方式遍历大型集合,则可能会成为问题。

StringBuilder在这些情况下,该类可提高性能。与其创建新strings的存储连接结果的方法,不如使用相同的对象。因此,如果您使用的stringBuilder.Append(a);话,您永远不会拥有“的旧值result”。


当然,这种存储效率是有代价的。当仅连接少量stringsa时StringBuilder,在速度方面通常效率较低,因为与不变string类相比,其开销更大。


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


2

原因是因为strings是一成不变的。串联时,string您将创建一个新的string。因此,当需要串联多个时,strings会创建很多objects。就内存而言,这并不会花费太多,因为每个string都使用一次。但是它确实给了额外的工作GC

StringBuilder但是,object每次都使用相同的内容,但这是以易于使用为代价的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.