简体   繁体   English

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

[英]How is C# string interpolation compiled?

I know that interpolation is syntactic sugar for string.Format() , but does it have any special behavior/recognition of when it is being used with a string formatting method? 我知道插值是string.Format()语法糖,但是当它与字符串格式化方法一起使用时,它是否有任何特殊的行为/识别?

If I have a method: 如果我有一个方法:

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

And the following call to it using interpolation: 以下使用插值调用它:

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

Which of the following calls lines is most equivalent to the compiled result of string interpolation? 以下哪个调用行最相当于字符串插值的编译结果?

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

Reasoning behind the question: Logging frameworks such as NLog typically defer string formatting until they have determined that a log message will actually be written. 问题背后的推理:诸如NLog之类的记录框架通常会推迟字符串格式化,直到确定将实际写入日志消息为止。 In general I prefer the string interpolation syntax, but I need to know if it may incur an extra performance penalty. 一般来说,我更喜欢字符串插值语法,但我需要知道它是否会产生额外的性能损失。

It is compiled in one of two ways. 它以两种方式之一编译。

If you use a string interpolation expression where a string is expected, it is compiled into a call to string.Format . 如果使用字符串插值表达式,其中需要一个string ,则将其编译为对string.Format的调用。

Basically, this: 基本上,这个:

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

is turned into this: 变成了这个:

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

See it for yourself in Try Roslyn . 在Try Roslyn中亲眼看看

Nothing magical here. 这里没什么神奇的。

Now, on the other hand, if you use it in a place where a FormattableString (a new type in .NET 4.6) is expected, it is compiled into a call to FormattableStringFactory.Create : 现在,另一方面,如果您在一个需要FormattableString (.NET 4.6中的新类型)的地方使用它,它将被编译为对FormattableStringFactory.Create的调用:

public void Test(FormattableString s)
{
}

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

The call there is turned into this: 那里的电话变成了这样:

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

See it for yourself in Try Roslyn . 在Try Roslyn中亲眼看看

So in essence, to answer your final question there: 所以从本质上讲,回答你的最后一个问题:

This call: 这个电话:

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

Will be translated to this: 将翻译成这个:

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

which will incur the cost of the formatting through string.Format before Print is even called. 这甚至会在调用Print之前通过string.Format产生格式化成本。

If you could add, or find, an overload of Print that takes a FormattableString , then you could defer the actual cost of string.Format until after you've figured out if you need to log. 如果您可以添加或找到带有FormattableStringPrint FormattableString ,那么您可以推迟string.Format的实际成本,直到您确定是否需要记录为止。 Whether this has a measurable different in runtime is hard to say. 这在运行时是否具有可测量的差异很难说。

See it for yourself in Try Roslyn . 在Try Roslyn中亲眼看看


Bonus Round 奖金回合

Not only is the actual formatting deferred, but the ToString method of FormattableString allows you to specify a IFormatProvider . 不仅延迟了实际格式,而且FormattableStringToString方法允许您指定IFormatProvider

This means that you can defer localized transformation as well. 这意味着您也可以推迟本地化转换。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM