如何编译C#字符串插值?

时间:2016-05-20 15:50:36

标签: c# string-formatting roslyn c#-6.0

我知道插值是string.Format()的语法糖,但是当它与字符串格式化方法一起使用时,它是否有任何特殊的行为/识别?

如果我有方法:

void Print(string format, params object[] parameters)

以下使用插值调用它:

Print($"{foo} {bar}");

以下哪一个调用行最能等同于字符串插值的编译结果?

Print(string.Format("{0} {1}", new[] { foo, bar }));
Print("{0} {1}", new[] { foo, bar });

问题背后的推理:NLog等日志记录框架通常会延迟字符串格式化,直到确定实际写入日志消息为止。一般来说,我更喜欢字符串插值语法,但我需要知道它是否会产生额外的性能损失。

1 个答案:

答案 0 :(得分:29)

它以两种方式之一编译。

如果您使用字符串插值表达式,其中需要string,则会将其编译为对string.Format的调用。

基本上,这个:

string s = $"now is {DateTime.Now}";

变成了这个:

string s = string.Format("now is {0}", DateTime.Now);

See it for yourself in Try Roslyn

这里没什么神奇的。

现在,另一方面,如果您在需要FormattableString(.NET 4.6中的新类型)的地方使用它,则会将其编译为对FormattableStringFactory.Create的调用:< / p>

public void Test(FormattableString s)
{
}

Test($"now is {DateTime.Now}");

那里的电话变成了这个:

Test(FormattableStringFactory.Create("now is {0}", DateTime.Now));

See it for yourself in Try Roslyn

所以从本质上说,回答你的最后一个问题:

这个电话:

Print($"{foo} {bar}");

将被翻译成:

Print(string.Format("{0} {1}", foo, bar));

会在string.Format被调用之前通过Print产生格式化费用。

如果你可以添加或找到Print的重载,需要FormattableString,那么你可以推迟string.Format的实际费用,直到你发现它为止如果你需要登录这在运行时是否具有可测量的差异很难说。

See it for yourself in Try Roslyn

奖金回合

不仅延迟了实际格式,而且ToString FormattableString方法允许您指定IFormatProvider

这意味着您也可以推迟本地化转换。

public static void Print(FormattableString s)
{
    Console.WriteLine("norwegian: " + s.ToString(CultureInfo.GetCultureInfo("nb-NO")));
    Console.WriteLine("us: " + s.ToString(CultureInfo.GetCultureInfo("en-US")));
    Console.WriteLine("swedish: " + s.ToString(CultureInfo.GetCultureInfo("sv-SE")));
}