Как скомпилирована строковая интерполяция С#?

Я знаю, что интерполяция является синтаксическим сахаром для 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

Он скомпилирован одним из двух способов.

Если вы используете выражение интерполяции строк, где ожидается 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));

который понесет стоимость форматирования через string.Format до того, как Print будет даже вызван.

Если вы могли бы добавить или найти перегрузку Print, которая принимает 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")));
}