Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# StringBuilder和'+';操作人员_C#_.net_Compiler Optimization - Fatal编程技术网

C# StringBuilder和'+';操作人员

C# StringBuilder和'+';操作人员,c#,.net,compiler-optimization,C#,.net,Compiler Optimization,我在这里维护这段代码,它通常有如下模式: StringBuilder result = new StringBuilder(); result.Append("{=" + field.Name + "={"); 这样做似乎浪费了大量无用的对象构造,我想重写如下: result.Append("{=").Append(field.Name).Append("={"); 第一个版本对GC施加了更大的压力,这是正确的吗?或者,在C#编译器中,如果字符串与字符串文字的连接不会创建临时对象,那么是否

我在这里维护这段代码,它通常有如下模式:

StringBuilder result = new StringBuilder();

result.Append("{=" + field.Name + "={");
这样做似乎浪费了大量无用的对象构造,我想重写如下:

result.Append("{=").Append(field.Name).Append("={");

第一个版本对GC施加了更大的压力,这是正确的吗?或者,在C#编译器中,如果字符串与字符串文字的连接不会创建临时对象,那么是否有一些优化?

我同意所有的答案,但对我来说,你需要理解C#中的字符串,以及它们实际上被“隐藏”处理的方式

当连接5个或5个以上的字符串时,StringBuilder的使用会自动进行。这是因为编译器本质上转换:

string a = b + c + d + e + f;
进入

因此,创建数组会有一个隐含的开销

我建议阅读Eric Lippert的以下内容,他在C#中编写了字符串连接:

请注意,
StringBuilder
是可变的,与
String
不同,它是专门为以这种方式构建字符串而设计的。尽管使用大字符串进行字符串连接很容易给GC带来明显的压力,但如果您使用的是
StringBuilder
,这通常不是一个问题

如果内存消耗是一个问题(对于大字符串可能是这样),并且您知道最终结果的大致长度,那么可以使用构造函数建议开始大小,并随着构建器的增长最小化内存重新分配

还请注意,您可以使用
AppendFormat
将变量插入常量字符串,例如:

result.Append("{=").Append(field.Name).Append("={");
变成:

result.AppendFormat("{{={0}={{", field.Name);
这会产生完全相同的结果,并且在很大程度上取决于偏好而不是性能


最后,如果
result
是整个字符串(而不是正在构建的更大字符串的一部分),只需使用
string.Format(“{{{0}={{”,field.Name)
string.Concat(“{=”,field.Name.={”)
而不是
StringBuilder
"虽然StringBuilder类通常比String类提供更好的性能,但您不应在需要操作字符串时自动使用StringBuilder替换字符串。性能取决于字符串的大小、为新字符串分配的内存量、应用程序正在执行的系统以及e操作类型。您应该准备好测试应用程序,以确定StringBuilder是否真的提供了显著的性能改进。“

我实际为此构建并运行了多个测试。要获得测试结果,请跳到底部。我使用了此基准测试方法:

public static string BenchmarkMethod(Action method, int iterations)
{
    var watch = new Stopwatch();
    var results = new List<TimeSpan>(iterations);
    for (int iteration = 0; iteration < iterations; iteration++)
    {
    watch.Start();
    method();
    watch.Stop();
    results.Add(watch.Elapsed);
    watch.Reset();
    }

    var builder = new StringBuilder();
    builder.Append("Method benchmarked: ");
    builder.Append(method.Method.ReflectedType);
    builder.Append(".");
    builder.AppendLine(method.Method.Name);
    builder.Append("Average time in ticks: ");
    builder.AppendLine(results.Average(t => t.Ticks).ToString());

    return builder.ToString();
}
以及:

其中
strings
是一个包含9个30个字母字符串的字符串数组

它们的范围从1到8个concats/附录。我最初编写它们是从1到6,使用3个字母字符串,并采集了10000个样本

更新:我已经得到了更多的样本(准确地说是100万)在字符串中添加更多的字母。显然,使用StringBuilder完全是对性能的浪费。在使用StringBuilder的30个字母中,使用
+
操作符所需的时间是使用
+
操作符所需时间的两倍……在现在需要几秒钟才能完成的测试中,我想我应该退出这个主题

最后更新:这也是非常重要的。使用
+
操作符和StringBuilder的区别在于当您在不同的行上进行连接时。这种方法实际上比使用StringBuilder花费的时间更长:

public static void StringConcatAltOperatorX8()
{
    var foo = strings[0];
    foo += strings[1];
    foo += strings[2];
    foo += strings[3];
    foo += strings[4];
    foo += strings[5];
    foo += strings[6];
    foo += strings[7];
    foo += strings[8];
}

因此,在每个字符串30个字母和100万个样本的情况下,在同一个调用中将所有字符串组合成一个字符串大约需要5.809297个刻度。将所有字符串组合成单独的行大约需要12.933227个刻度。使用StringBuilder需要11.27558个刻度。我对回复的长度表示歉意。这是我需要在我的self.

编译器足够聪明,可以生成对字符串之一的调用。Concat()重载。如果你只使用StringBuilder进行连接,那么你的情况实际上会更糟。这就是你使用StringBuilder的全部目的吗?如果是,这是浪费。只使用字符串连接。@AntP:我想OP忽略了循环,他只是想知道字符串连接和StringBuilder.Append或仅Append版本。我不确定,但我听说如果在编译时连接的对象数量是固定的,那么它会得到很好的优化,不会浪费内存。其次,StringBuilder可能会比短字符串连接浪费更多的内存和CPU时间,因此它比concat少量字符串连接更可取t字符串,而不是为它们构建一个StringBuilder“It.Just.dos.not.Matter!”(几乎所有时间)我不知道这一点,谢谢。尽管通过查看Concat重载,这种情况仅在一次正确连接超过4个字符串时发生,但这是
StringBuilder
的唯一用例,当连接需要在多行或循环中发生时。否则,您只需使用二进制加法运算符。
public static void StringConcatOperatorX8()
{
    var foo = strings[0] + strings[1] + strings[2] + strings[3] + strings[4] + strings[5] + strings[6] + strings[7] + strings[8];
}
public static void StringBuilderAppendsX8()
{
    var builder = new StringBuilder();
    builder.Append(strings[0]);
    builder.Append(strings[1]);
    builder.Append(strings[2]);
    builder.Append(strings[3]);
    builder.Append(strings[4]);
    builder.Append(strings[5]);
    builder.Append(strings[6]);
    builder.Append(strings[7]);
    builder.Append(strings[8]);

    var result = builder.ToString();
}
public static void StringConcatAltOperatorX8()
{
    var foo = strings[0];
    foo += strings[1];
    foo += strings[2];
    foo += strings[3];
    foo += strings[4];
    foo += strings[5];
    foo += strings[6];
    foo += strings[7];
    foo += strings[8];
}