C#6.0和#34;字符串"之间的性能差异和$"字符串"

时间:2017-10-05 17:18:18

标签: c# c#-6.0 string-interpolation syntactic-sugar

我在C#6.0中有两个代码:

示例1:

var foo = "Some text, " +
          $"some other {bar}, " +
          "end text.";

示例2:

var foo = $"Some text, " +
          $"some other {bar}, " +
          $"end text.";

显然,这两个代码都会产生相同的结果,但第二个代码在美学上更加美观(这是我的意见,请记住每个代码都有你的。)

问题:
如果不需要$,是否有问题(性能或其他)写一个前缀为$的字符串。

修改 回答一些抱怨:

  

第二个是可怕的。不要对没有内插的字符串使用字符串插值符号($)。对于任何查看代码的人(或未来,更有经验的人)来说,这会让人感到困惑

这完全是您的看法,我在这里有一个团队,有10位高级C#开发人员,他们都同意第二个更清晰。

  

@ChetanRanpariya这不是真的。插值字符串是用于调用string.Format的语法糖,必须调用它(从而影响性能)。

你需要提供证明你在说什么。

4 个答案:

答案 0 :(得分:5)

$创建一个插值字符串,与使用String.Format相同。如果将+与字符串文字一起使用,则编译器会优化代码以避免连接在一起。使用插值字符串可能会阻止此优化。

修改

性能和文字优化测试​​

好吧,我刚刚测试了这个,似乎没有任何性能问题。显然,如果没有$,编译器会忽略{}并且不使用String.Format。我的测试结果显示在600万个构造50长度字符串的循环中。

  • String.Format:23700 ms
  • $"a{null}" +:22650 ms
  • $"a" +:13 ms
  • "a" +:13 ms
  • "a"+连接:700毫秒

另外,看IL也没什么区别。因此,性能方面,您发布的代码执行和优化相同,$被忽略,只是使用{}时的一个因素。

<强>语法

当然可以讨论这是否是好的语法。我可以想到支持和反对的论据。

赞成

  • 如果$已经存在,则添加新参数会更容易
  • 在多行文字的行之间移动参数更容易
  • 它提供多行文字
  • 的行之间的一致性

缺点

  • 看起来不同......最不惊讶的原则。
  • 为什么要添加未使用的语法?
  • 它不会使插入的变量显而易见

对我来说,倾斜点是我看到$并希望看到{}和一个参数。如果我看不到我期望看到的东西,它会导致认知失调。另一方面,我可以想象它提供的流动性可能会出现这种情况。可能很远,它取决于开发组和目标。

答案 1 :(得分:1)

这很容易做一些简单的诊断。 Maccettura在评论中显示,当它被编译时没有区别,因为它只为每个字符串调用一次String.Format而不管额外的插值,但是这个测试也会支持它。

int rounds = 50;
int timesToCreateString = 50000;
Stopwatch sw = new Stopwatch();
double first = 0;
double second = 0;
for (int i = 0; i < rounds; i++)
{
    sw.Start();
    for (int bar = 0; bar < timesToCreateString; bar++)
    {
        var foo = "Some text, " +
                 $"some other {bar}, " +
                  "end text.";
    }
    sw.Stop();
    first += sw.ElapsedTicks;
    sw.Reset();
    sw.Start();
    for (int bar = 0; bar < timesToCreateString; bar++)
    {                
        var foo = $"Some text, " +
                  $"some other {bar}, " +
                  $"end text.";
    }
    sw.Stop();
    second += sw.ElapsedTicks;
    sw.Reset();
}
Console.WriteLine("Average first test: " + first / rounds);
Console.WriteLine("Average second test: " + second / rounds);
Console.ReadKey();
// program ran 3 times and results.
//Average first test: 54822.04
//Average second test: 55083.86

//Average first test: 54317.66
//Average second test: 54807.8

//Average first test: 49873.12
//Average second test: 48264.36

答案 2 :(得分:1)

看看IL:

第一个代码:

var bar = "a";
var foo = "b" + $"{bar}";

第一次IL:

IL_0000:  nop         
IL_0001:  ldstr       "a"
IL_0006:  stloc.0     // bar
IL_0007:  ldstr       "b"
IL_000C:  ldstr       "{0}"
IL_0011:  ldloc.0     // bar
IL_0012:  call        System.String.Format
IL_0017:  call        System.String.Concat
IL_001C:  stloc.1     // foo
IL_001D:  ret         

第二个代码:

var bar = "a";
var foo = $"b" + $"{bar}";

第二次IL:

IL_0000:  nop         
IL_0001:  ldstr       "a"
IL_0006:  stloc.0     // bar
IL_0007:  ldstr       "b"
IL_000C:  ldstr       "{0}"
IL_0011:  ldloc.0     // bar
IL_0012:  call        System.String.Format
IL_0017:  call        System.String.Concat
IL_001C:  stloc.1     // foo
IL_001D:  ret         

结论:

两个代码之间没有编译差异。

PS :( IL由Linqpad 5.22.02生成)。

答案 3 :(得分:1)

您可以选择自己喜欢的任何内容。确实$转换为string.format(参见https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interpolated-strings),但编译器足够聪明,可以过滤掉未格式化的代码。