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

我知道插值是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等日志框架通常会延迟字符串格式化,直到确定实际写入日志消息为止。 一般来说,我更喜欢字符串插值语法,但我需要知道它是否会产生额外的性能损失。

它以两种方式之一编译。

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

基本上,这个:

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

变成这样:

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

在Try Roslyn中亲眼看看 。

这里没什么神奇的。

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

 public void Test(FormattableString s) { } Test($"now is {DateTime.Now}"); 

那里的电话变成了这个:

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

在Try Roslyn中亲眼看看 。

所以从本质上讲,在那里回答你的最后一个问题:

这个电话:

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

将翻译成这个:

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

这甚至会在调用Print之前通过string.Format产生格式化的代价。

如果您可以添加或查找带有FormattableStringPrint FormattableString ,那么您可以推迟string.Format的实际开销,直到您确定是否需要记录为止。 这在运行时是否具有可测量的差异很难说。

在Try Roslyn中亲眼看看 。


奖金回合

不仅延迟了实际格式,而且FormattableStringToString方法允许您指定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"))); }