wake-up-neo.net

Warum funktioniert die String-Interpolation nicht mit const-Strings?

Warum funktioniert die String-Interpolation in c # nicht mit const-Strings? Zum Beispiel:

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

Aus meiner Sicht ist alles zur Kompilierzeit bekannt. Oder ist das eine Funktion, die später hinzugefügt wird?

Compiler-Nachricht:

Der Ausdruck, der "DynamicWebApiBuilder.WEB_API_PROJECT" zugewiesen ist, muss konstant sein.

Danke vielmals!

19
BendEg

Interpolierte Zeichenfolgen werden einfach in Aufrufe von string.Format konvertiert. Ihre obige Zeile liest sich also tatsächlich

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

Und dies ist keine Kompilierungszeitkonstante, da ein Methodenaufruf enthalten ist.


Auf der anderen Seite kann der Compiler string concatenation (von einfachen, konstanten String-Literalen) ausführen. Dies funktioniert also:

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

oder von const zu static readonly wechseln:

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

die Zeichenfolge wird also beim ersten Zugriff auf ein Mitglied des deklarierenden Typs initialisiert (und string.Format aufgerufen).

33
René Vogt

Eine weitere Erklärung dafür, warum Zeichenfolgeninterpolationsausdrücke nicht als Konstanten betrachtet werden, ist, dass sie nicht konstant sind , auch wenn alle ihre Eingaben Konstanten sind. Insbesondere variieren sie je nach aktueller Kultur. Versuchen Sie den folgenden Code auszuführen:

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

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

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

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

Ihre Ausgabe ist:

3.14
3,14

Beachten Sie, dass die Ausgabe unterschiedlich ist, obwohl der Ausdruck der Zeichenfolgeninterpolation in beiden Fällen derselbe ist. Mit const string pi = $"{3.14}" wäre also nicht klar, welchen Code der Compiler generieren soll.

15
svick

Es gibt eine Diskussion im Roslyn-Projekt bei roslyn , die die folgende Schlussfolgerung abschließt:

Lesen Sie den Auszug:

Es ist kein Fehler, es wurde explizit so entworfen, dass es so funktioniert. Sie mögen es nicht, macht es nicht zu einem Fehler. String.Format wird nicht zum Verketten von Strings benötigt, aber das ist nicht was tust du. Sie interpolieren sie und String.Format ist erforderlich, basierend auf der Spezifikation und Implementierung von wie Interpolation funktioniert in C #. 

Wenn Sie Zeichenketten verketten möchten, gehen Sie Recht voraus und verwenden Sie dieselbe Syntax, die seit C # 1.0 ..__ funktioniert hat. Wenn Sie die Implementierung ändern, um sich je nach Verwendung anders zu verhalten, würde unerwartete Ergebnisse erzeugen:

  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

Sogar die Aussage:

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

Der Compiler gibt einen Fehler aus:

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

Die Variable 'WEB_API_ROOT' sollte im selben Kontext definiert werden 

Für die Frage von OP: Warum funktioniert die String-Interpolation nicht mit Const-Strings? Weitere Informationen finden Sie unter .NET Compiler Platform ("Roslyn") -String Interpolation for c #

5
M.Hassan

Eine Konstante, die mit string.Format verwendet wird, soll ihrer Natur nach mit einer bestimmten Anzahl von Argumenten arbeiten, die jeweils eine vorbestimmte Bedeutung haben.

Mit anderen Worten, wenn Sie diese Konstante erstellen:

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

Um es verwenden zu können, müssen Sie zwei Argumente haben, die wahrscheinlich eine string und eine DateTime sein sollen. 

Wir haben also schon vor der String-Interpolation die Konstante als Funktion verwendet. Mit anderen Worten, anstatt die Konstante zu trennen, hätte es vielleicht sinnvoller sein können, sie stattdessen in eine Funktion zu setzen, wie etwa:

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

Es ist immer noch dasselbe, nur dass die Konstante (String-Literal) jetzt mit der Funktion und den Argumenten lokalisiert wird, die sie verwenden. Sie können genauso gut zusammen sein, da die Formatzeichenfolge für andere Zwecke unbrauchbar ist. Außerdem können Sie jetzt die Absicht der Argumente sehen, die auf die Formatzeichenfolge angewendet werden.

Wenn wir es so betrachten, wird die ähnliche Verwendung der String-Interpolation offensichtlich:

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

Was ist, wenn wir mehrere Formatzeichenfolgen haben und zur Laufzeit eine bestimmte auswählen möchten?

Anstatt den zu verwendenden String auszuwählen, können wir eine Funktion auswählen:

delegate string FooDescriptionFunction(string fooName, DateTime createdDate);

Dann könnten wir Implementierungen wie folgt deklarieren:

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

Oder noch besser:

delegate string FooDescriptionFunction(Foo foo);

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