Почему интерполяция строк не работает с константными строками

Почему интерполяция строк в С# не работает со строками const? Например:

private const string WEB_API_ROOT = "/private/WebApi/";
private const string WEB_API_PROJECT = $"{WEB_API_ROOT}project.json";

С моей точки зрения, все известно во время компиляции. Или это функция, которая будет добавлена позже?

Сообщение компилятора:

Выражение, присвоенное "DynamicWebApiBuilder.WEB_API_PROJECT", должно быть постоянным.

Большое спасибо!

Ответ 1

Интерполированные строки просто преобразуются в вызовы string.Format. Таким образом, ваша надпись на самом деле читает

private const string WEB_API_PROJECT = string.Format("{0}project.json", WEB_API_ROOT);

И это не постоянная времени компиляции, так как включен вызов метода.


С другой стороны, конкатенация строк (простых, постоянных строковых литералов) может быть выполнена компилятором, поэтому это будет работать:

private const string WEB_API_ROOT = "/private/WebApi/";
private const string WEB_API_PROJECT = WEB_API_ROOT + "project.json";

или перейти от const к static readonly:

private static readonly string WEB_API_PROJECT = $"{WEB_API_ROOT}project.json";

поэтому строка инициализируется (и называется string.Format) при первом доступе к любому члену типа объявления.

Ответ 2

Дополнительное объяснение того, почему строковые интерполяционные выражения не считаются константами, состоит в том, что они не являются постоянными, даже если все их входы являются константами. В частности, они варьируются в зависимости от текущей культуры. Попробуйте выполнить следующий код:

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

Console.WriteLine($"{3.14}");

CultureInfo.CurrentCulture = new CultureInfo("cs-CZ");

Console.WriteLine($"{3.14}");

Его выход:

3.14
3,14

Обратите внимание, что вывод отличается, хотя выражение интерполяции строк в обоих случаях одинаково. Итак, с const string pi = $"{3.14}", неясно, какой код должен генерировать компилятор.

Ответ 3

В проекте Roslyn в roslyn есть дискуссия, в которой завершается следующий вывод:

Прочтите выдержку:

Это не ошибка, она была явно разработана таким образом. Вам не нравится, что это не ошибка. String.Format не требуется для конкатенации строк, но это не то, что вы делаете. Вы интерполируете их, и String.Format необходим для этого на основе спецификации и реализации того, как интерполяция работает на С#.

Если вы хотите объединить строки, перейдите прямо вперед и используйте тот же синтаксис, который работал с С# 1.0. Изменение реализации, чтобы вести себя по-разному на основе использования, привело бы к неожиданным результатам:

  const string FOO = "FOO";
  const string BAR = "BAR";
  string foobar = $"{FOO}{BAR}";
  const string FOOBAR = $"{FOO}{BAR}"; // illegal today

  Debug.Assert(foobar == FOOBAR); // might not always be true

Даже выражение:

  private static readonly string WEB_API_PROJECT = $"{WEB_API_ROOT}project.json";

Компилятор вызывает ошибку:

 "The name 'WEB_API_ROOT' does not exist in the current context". 

Переменная "WEB_API_ROOT" должна быть определена в том же контексте

Итак, для вопроса OP: Почему интерполяция строк не работает с константными строками? Ответ: Это спецификации С# 6. для более подробной информации читайте .NET Compiler Platform ("Roslyn") -String Интерполяция для С#