5

我有一个StringBuilder对象,我在其中添加一些字符串,如下所示:

我想知道哪个是更好的方法,第一个是这样的:

StringBuilder sb = new StringBuilder();
sb.Append("Hello" + "How" + "are" + "you");

第二个是:

StringBuilder sb = new StringBuilder();
sb.Append("Hello").Append("How").Append("are").Append("you");
4

5 回答 5

10

在您当前的示例中,字符串文字:

"Hello" + "How" + "are" + "you"

将被编译器编译成一个常量字符串文字,因此它在技术上比:

sb.Append("Hello").Append("How").Append("are").Append("you");

但是,您是否使用字符串变量:

sb.Append(s1 + s2 + s3 + s4);

然后后者会更快,因为前者可能会在将最终字符串传递给方法之前创建一系列字符串(因为连接)Append,而后者将避免额外的字符串创建(但权衡额外的方法调用和内部缓冲区调整大小)。

更新:为了更清楚起见,在这种只有 4 个项目被连接的确切情况下,编译器将发出对 的调用String.Concat(string, string, string, string),知道字符串的长度和数量将比StringBuilder.

于 2012-08-13T16:03:20.237 回答
7

第一个会更有效率。编译器会将其转换为以下单个调用:

StringBuilder sb = new StringBuilder();
sb.Append("HelloHowareyou");

衡量绩效

知道哪个更快的最好方法是测量它。我会直截了当:这是结果(时间越短意味着速度越快):

sb.Append("Hello" + "How" + "are" + "you")                  : 11.428s
sb.Append("Hello").Append("How").Append("are").Append("you"): 15.314s
sb.Append(a + b + c + d)                                    : 21.970s
sb.Append(a).Append(b).Append(c).Append(d)                  : 15.529s

给出的数字是在紧密循环中执行 1 亿次操作的秒数。

结论

  • 最快的是使用字符串文字和+.
  • 但是,如果您有变量,则 usingAppend+. 第一个版本较慢,因为需要额外调用String.Concat.

如果您想自己测试,这是我用来获取上述时间的程序:

using System;
using System.Text;

public class Program
{
    public static void Main()
    {
        DateTime start, end;
        int numberOfIterations = 100000000;
        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Hello" + "How" + "are" + "you");
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(\"Hello\" + \"How\" + \"are\" + \"you\")", start, end);

        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Hello").Append("How").Append("are").Append("you");
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(\"Hello\").Append(\"How\").Append(\"are\").Append(\"you\")", start, end);

        string a = "Hello";
        string b = "How";
        string c = "are";
        string d = "you";

        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(a + b + c + d);
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(a + b + c + d)", start, end);

        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(a).Append(b).Append(c).Append(d);
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(a).Append(b).Append(c).Append(d)", start, end);

        Console.ReadLine();
    }

    private static void DisplayResult(string name, DateTime start, DateTime end)
    {
        Console.WriteLine("{0,-60}: {1,6:0.000}s", name, (end - start).TotalSeconds);
    }
}
于 2012-08-13T16:03:06.480 回答
4

编译器将在编译时连接字符串常量。如果您连接的字符串表达式不超过四个,编译器将发出调用String.Concat

s + t + u + v ==> String.Concat(s, t, u, v)

这比 执行得更快StringBuilder,因为StringBuilder可能需要调整其内部缓冲区的大小,同时Concat可以提前计算总的结果长度。但是,如果您事先知道结果字符串的最大长度,则可以StringBuilder通过指定初始工作缓冲区大小来初始化

var sb = new StringBuilder(initialBufferSize);

StringBuilder通常在循环和其他动态场景中使用,并且比s += t在这种情况下执行得更快。

于 2012-08-13T16:21:25.047 回答
0

在第一种情况下,编译器将构造一个字符串,因此您只需调用 Append 一次。但是,我怀疑这会产生很大的不同。你的测量结果显示了什么?

于 2012-08-13T16:03:27.353 回答
-5

第二个是更好的方法。字符串是不可变的,这意味着当您使用 sb.Append("Hello" + "How" + "Are" + "You") 时,您正在创建字符串的多个副本

例如

"Hello"

然后

"HelloHow"

然后

"HelloHowAre"

等等

第二段代码的性能要高得多

编辑:当然这没有考虑编译器优化,但最好按预期使用该类

好的,正如人们指出的那样,因为这些是文字,编译器负责优化这些操作 - 但我的观点是,字符串连接是 StringBuilder 试图避免的事情

例如,循环多次:

var someString = "";

foreach (var s in someListOfStrings) 
{
    someString += s;
}

不如做:

var sb = new StringBuilder();

foreach(var s in someListOfStrings)
{
    sb.Append(s);
}

sb.ToString();

因为这可能会更快,因为正如我之前所说,字符串是不可变的

我认为 OP 一般是在谈论使用串联,因为

sb.Append("Hello" + "How");

似乎完全没有意义

sb.Append("HelloHow");

会更合乎逻辑...?

在我看来,在 OP 看来,占位符文本最终会变成一堆变量......

于 2012-08-13T16:03:52.697 回答