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

Mer*_*rad 21 c# string-formatting roslyn c#-6.0

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

如果我有一个方法:

void Print(string format, params object[] parameters)
Run Code Online (Sandbox Code Playgroud)

以下使用插值调用它:

Print($"{foo} {bar}");
Run Code Online (Sandbox Code Playgroud)

以下哪个调用行最相当于字符串插值的编译结果?

Print(string.Format("{0} {1}", new[] { foo, bar }));
Print("{0} {1}", new[] { foo, bar });
Run Code Online (Sandbox Code Playgroud)

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

ang*_*son 29

它以两种方式之一编译.

如果你使用字符串插值表达式,其中a string是预期的,它被编译成一个调用string.Format.

基本上,这个:

string s = $"now is {DateTime.Now}";
Run Code Online (Sandbox Code Playgroud)

变成了这个:

string s = string.Format("now is {0}", DateTime.Now);
Run Code Online (Sandbox Code Playgroud)

在Try Roslyn中亲眼看看.

这里没什么神奇的.

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

public void Test(FormattableString s)
{
}

Test($"now is {DateTime.Now}");
Run Code Online (Sandbox Code Playgroud)

那里的电话变成了这样:

Test(FormattableStringFactory.Create("now is {0}", DateTime.Now));
Run Code Online (Sandbox Code Playgroud)

在Try Roslyn中亲眼看看.

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

这个电话:

Print($"{foo} {bar}");
Run Code Online (Sandbox Code Playgroud)

将翻译成这个:

Print(string.Format("{0} {1}", foo, bar));
Run Code Online (Sandbox Code Playgroud)

甚至可以调用string.Format以前的格式化成本Print.

如果您可以添加或找到Print需要a 的重载FormattableString,那么您可以推迟实际成本,string.Format直到您确定是否需要记录为止.这在运行时是否具有可测量的差异很难说.

在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")));
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,添加接受 `FormattableString` 的重载无济于事,因为 `string` 在重载解析期间具有更高的优先级。您将不得不使用单独的方法名称。 (2认同)