2016-09-12 6 views
11

C#での文字列補間がconst文字列で機能しないのはなぜですか?たとえば:文字列補間がconst文字列で機能しない理由

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

私の視点からは、すべてがコンパイル時に知られています。それとも、後で追加される機能ですか?

コンパイラメッセージ:

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

どうもありがとう!

+8

補間された文字列は単に 'string.Format'呼び出しに変換されます。 – juharr

+3

回避策としては、 'const'を' static readonly'に置き換えてください。 –

+4

@juharr:渡すパラメータがこの定数を初期化するのに使用できる別の定数であるかどうかをコンパイラがチェックできなかった理由を説明しません。連結された文字列リテラルで使用できます。だから、なぜそれが結合された文字列リテラルで許可されていない、コンパイラは同じテクニックを使用することができます。 –

答えて

22

補間された文字列は、単にstring.Formatの呼び出しに変換されます。だからあなたの上の行は、実際に

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

を読み込み、メソッドの呼び出しが含まれているので、これは一定の時間をコンパイルされていません。一方


、(単純な、一定の文字列リテラルの)列連結は、コンパイラによって行うことができるので、これは動作します:

constから static readonly
private const string WEB_API_ROOT = "/private/WebApi/"; 
private const string WEB_API_PROJECT = WEB_API_ROOT + "project.json"; 

またはスイッチ。すべての私への最初のアクセスで

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

ので文字列が初期化されます(と string.Formatと呼ばれます)宣言型のmber。

+0

それは理にかなっています。ありがとうたくさん:) – BendEg

+1

そのシンプルなconcationationはっきりしている、ちょうど私もこの新しいC#6の機能をここで使うことができると思った。 – BendEg

+0

@Rene、[private static readonly string]を使用しても、コンパイラは、 "名前 'WEB_API_ROOT'が現在のコンテキストに存在しません"というエラーを発生させます。変数 'WEB_API_ROOT'は同じコンテキストで定義する必要があります。 –

9

文字列補間式が定数と見なされない理由についての補足は、です。すべての入力が定数であっても、定数はではありません。具体的には、現在の文化に基づいて異なります。

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}"では、コンパイラがどのコードを生成するべきかは明確ではありません。

4

次の結論確定roslynでのロザリンプロジェクトでの議論があります:

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 

でも声明:

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の質問には、だから、同じコンテキストで

を定義する必要があります。なぜ、文字列の補間はCONST文字列で動作していないのですか? 答え:C#6仕様です。詳細はread .NET Compiler Platform ("Roslyn") -String Interpolation for C#

+0

ここでのtakeawayは多かれ少なかれそうであることに注意してください:フォーマットされたすべての文字列を変更する仮想のデフォルトカルチャを定義(および設定)することは、 'string.Format()'呼び出しの戻り値を変更します実行時に 'const'' string's、**のみを実行します。その文化チェックは静的初期化子の間に起こる可能性が高いが、 'const'文字列値セットはコンパイル時にのみ起こるので、' const'補間文字列は実行時に補間文字列の値と等しくならないコンパイル時のカルチャは実行時のカルチャではありません。 – jrh