Why does interpolating a const string result in a compiler error?

谁都会走 提交于 2019-12-20 16:27:10

问题


Why does string interpolation in c# does not work with const strings? For example:

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

From my point of view, everything is known at compile time. Or is that a feature that will be added later?

Compiler message:

The expression being assigned to 'DynamicWebApiBuilder.WEB_API_PROJECT' must be constant.

Thanks a lot!


回答1:


Interpolated strings are simply converted to calls to string.Format. So your above line actually reads

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

And this is not compile time constant as a method call is included.


On the other hand, string concatenation (of simple, constant string literals) can be done by the compiler, so this will work:

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

or switch from const to static readonly:

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

so the string is initialized (and string.Format called) at the first access to any member of the declaring type.




回答2:


An additional explanation why string interpolation expressions are not considered constants is that they are not constant, even if all their inputs are constants. Specifically, they vary based on the current culture. Try executing the following code:

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

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

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

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

Its output is:

3.14
3,14

Note that the output is different, even though the string interpolation expression is the same in both cases. So, with const string pi = $"{3.14}", it wouldn't be clear what code should the compiler generate.




回答3:


There is a discussion in Roslyn project at roslyn that finalize the following conclusion:

Read the excerpt:

It's not a bug, it was explicitly designed to function like this. You not liking it doesn't make it a bug. String.Format isn't needed for concatenating strings, but that's not what you're doing. You're interpolating them, and String.Format is needed for that based on the spec and implementation of how interpolation works in C#.

If you want to concatenate strings, go right ahead and use the same syntax that has worked since C# 1.0. Changing the implementation to behave differently based on usage would produce unexpected results:

  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

Even the statement:

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

The compiler raise an error:

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

The variable 'WEB_API_ROOT' should be defined in the same context

So, for the question of OP: Why does string interpolation is not working with const strings? Answer: It's by C# 6 specs. for more details read .NET Compiler Platform ("Roslyn") -String Interpolation for C#




回答4:


A constant used with string.Format would, by its nature, be intended to work with a specific number of arguments which each have a predetermined meaning.

In other words, if you create this constant:

const string FooFormat = "Foo named '{0}' was created on {1}.";

Then in order to use it you must have two arguments which are probably supposed to be a string and a DateTime.

So even before string interpolation we were in a sense using the constant as a function. In other words, instead of separating the constant, it might have made more sense to put it in a function instead, like this:

string FormatFooDescription(string fooName, DateTime createdDate) =>
    string.Format("Foo named '{0}' was created on {1}.", fooName, createdDate);

It's still the same thing, except that the constant (string literal) is now located with the function and arguments that use it. They might as well be together, because the format string is useless for any other purpose. What's more, now you can see the intent of the arguments that are applied to the format string.

When we look at it that way, the similar use of string interpolation becomes obvious:

string FormatFooDescription(string fooName, DateTime createdDate) =>
    $"Foo named '{fooName}' was created on {createdDate}.";

What if we have multiple format strings and we want to choose a particular one at runtime?

Instead of selecting which string to use, we could select a function:

delegate string FooDescriptionFunction(string fooName, DateTime createdDate);

Then we could declare implementations like this:

static FooDescriptionFunction FormatFoo { get; } = (fooName, createdDate) => 
    $"Foo named '{fooName}' was created on {createdDate}.";

Or, better yet:

delegate string FooDescriptionFunction(Foo foo);

static FooDescriptionFunction FormatFoo { get; } = (foo) => 
    $"Foo named '{foo.Name}' was created on {foo.CreatedDate}.";
}


来源:https://stackoverflow.com/questions/39451921/why-does-interpolating-a-const-string-result-in-a-compiler-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!