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

How is C# string interpolation compiled?

我知道插值是 string.Format() 的语法糖,但它在与字符串格式化方法一起使用时有什么特殊的 behavior/recognition 吗?

如果我有方法:

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);

See it for yourself in 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));

See it for yourself in Try Roslyn.

因此,从本质上讲,在这里回答您的最后一个问题:

这次通话:

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

将翻译为:

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

这将在调用 Print 之前通过 string.Format 产生格式化成本。

如果您可以添加或找到需要 FormattableStringPrint 重载,那么您可以将 string.Format 的实际成本推迟到您弄清楚之后如果你需要登录。这在运行时是否有可测量的差异很难说。

See it for yourself in 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")));
}