C# Language String-Interpolation


Beispiel

Durch die String-Interpolation kann der Entwickler variables und Text zu einem String kombinieren.


Basisbeispiel

Es werden zwei int Variablen erstellt: foo und bar .

int foo = 34;
int bar = 42;

string resultString = $"The foo is {foo}, and the bar is {bar}.";

Console.WriteLine(resultString);

Ausgabe :

Das Foo ist 34 und die Bar ist 42.

Demo anzeigen

Klammern innerhalb von Strings können wie folgt verwendet werden:

var foo = 34;
var bar = 42;

// String interpolation notation (new style)
Console.WriteLine($"The foo is {{foo}}, and the bar is {{bar}}.");

Dies erzeugt die folgende Ausgabe:

Das Foo ist {Foo} und die Bar ist {Bar}.


Verwenden der Interpolation mit wörtlichen String-Literalen

Die Verwendung von @ vor dem String bewirkt, dass der String wörtlich interpretiert wird. So bleiben beispielsweise Unicode-Zeichen oder Zeilenumbrüche genauso wie sie eingegeben wurden. Dies wirkt sich jedoch nicht auf die Ausdrücke in einer interpolierten Zeichenfolge aus, wie im folgenden Beispiel gezeigt:

Console.WriteLine($@"In case it wasn't clear:
\u00B9
The foo
is {foo},
and the bar
is {bar}.");
Ausgabe:

Falls es nicht klar war:
\ u00B9
Das foo
ist 34,
und die Bar
ist 42.

Demo anzeigen


Ausdrücke

Bei der String-Interpolation können auch Ausdrücke in geschweiften Klammern {} ausgewertet werden. Das Ergebnis wird an der entsprechenden Stelle in der Zeichenfolge eingefügt. Um beispielsweise das Maximum von foo und bar zu berechnen und einzufügen, verwenden Sie Math.Max innerhalb der geschweiften Klammern:

Console.WriteLine($"And the greater one is: { Math.Max(foo, bar) }");

Ausgabe:

Und der größere ist: 42

Hinweis: Alle führenden oder nachgestellten Leerzeichen (einschließlich Leerzeichen, Tabulatorzeichen und CRLF / Zeilenumbruch) zwischen der geschweiften Klammer und dem Ausdruck werden vollständig ignoriert und nicht in die Ausgabe aufgenommen

Demo anzeigen

Als weiteres Beispiel können Variablen als Währung formatiert werden:

Console.WriteLine($"Foo formatted as a currency to 4 decimal places: {foo:c4}");

Ausgabe:

Foo als Währung mit 4 Dezimalstellen formatiert: 34,0000 USD

Demo anzeigen

Oder sie können als Datumsangaben formatiert werden:

Console.WriteLine($"Today is: {DateTime.Today:dddd, MMMM dd - yyyy}");

Ausgabe:

Heute ist: Montag, 20. Juli - 2015

Demo anzeigen

Anweisungen mit einem bedingten (ternären) Operator können auch innerhalb der Interpolation ausgewertet werden. Diese müssen jedoch in Klammern eingeschlossen werden, da der Doppelpunkt andernfalls verwendet wird, um die Formatierung wie oben gezeigt anzuzeigen:

Console.WriteLine($"{(foo > bar ? "Foo is larger than bar!" : "Bar is larger than foo!")}");

Ausgabe:

Bar ist größer als Foo!

Demo anzeigen

Bedingte Ausdrücke und Formatbezeichner können gemischt werden:

Console.WriteLine($"Environment: {(Environment.Is64BitProcess ? 64 : 32):00'-bit'} process");

Ausgabe:

Umgebung: 32-Bit-Prozess


Escape-Sequenzen

Die umgekehrten Schrägstriche ( \ ) und Anführungszeichen ( " ) werden durchgängig für interpolierte Zeichenfolgen wie für nicht interpolierte Zeichenfolgen verwendet.

Console.WriteLine($"Foo is: {foo}. In a non-verbatim string, we need to escape \" and \\ with backslashes.");
Console.WriteLine($@"Foo is: {foo}. In a verbatim string, we need to escape "" with an extra quote, but we don't need to escape \");

Ausgabe:

Foo ist 34. In einer nicht-wortgetreuen Zeichenfolge müssen wir "und \ mit Backslashes" abbrechen.
Foo ist 34. In einer wörtlichen Zeichenfolge müssen wir mit einem zusätzlichen Anführungszeichen ""

Um eine geschweifte Klammer { oder } in eine interpolierte Zeichenfolge aufzunehmen, verwenden Sie zwei geschweifte Klammern {{ oder }} :

$"{{foo}} is: {foo}"

Ausgabe:

{foo} ist: 34

Demo anzeigen


FormattableString-Typ

Der Typ eines $"..." Zeichenfolgeninterpolationsausdrucks ist nicht immer eine einfache Zeichenfolge. Der Compiler entscheidet je nach Kontext, welchen Typ er zuweisen soll:

string s = $"hello, {name}";
System.FormattableString s = $"Hello, {name}";
System.IFormattable s = $"Hello, {name}";

Dies ist auch die Reihenfolge der Typeinstellung, wenn der Compiler auswählen muss, welche überladene Methode aufgerufen wird.

Ein neuer Typ , System.FormattableString , repräsentiert eine zusammengesetzte System.FormattableString zusammen mit den zu formatierenden Argumenten. Verwenden Sie diese Option, um Anwendungen zu schreiben, die die Interpolationsargumente speziell behandeln:

public void AddLogItem(FormattableString formattableString)
{
    foreach (var arg in formattableString.GetArguments())
    {
        // do something to interpolation argument 'arg'
    }

    // use the standard interpolation and the current culture info
    // to get an ordinary String:
    var formatted = formattableString.ToString();

    // ...
}

Rufen Sie die obige Methode auf mit:

AddLogItem($"The foo is {foo}, and the bar is {bar}.");
Zum Beispiel könnte man sich entscheiden, die Leistungskosten für die Formatierung der Zeichenfolge nicht zu tragen, wenn die Protokollierungsstufe das Protokollelement bereits herausfiltert.

Implizite Konvertierungen

Es gibt implizite Typkonvertierungen aus einer interpolierten Zeichenfolge:

var s = $"Foo: {foo}";
System.IFormattable s = $"Foo: {foo}";
Sie können auch eine IFormattable Variable IFormattable , mit der Sie die Zeichenfolge mit einem unveränderlichen Kontext konvertieren können:
var s = $"Bar: {bar}";
System.FormattableString s = $"Bar: {bar}";

Aktuelle und invariante Kulturmethoden

Wenn die Codeanalyse aktiviert ist, wird bei allen interpolierten Zeichenfolgen die Warnung CA1305 ( IFormatProvider ) IFormatProvider . Eine statische Methode kann verwendet werden, um die aktuelle Kultur anzuwenden.

public static class Culture
{
    public static string Current(FormattableString formattableString)
    {
        return formattableString?.ToString(CultureInfo.CurrentCulture);
    }
    public static string Invariant(FormattableString formattableString)
    {
        return formattableString?.ToString(CultureInfo.InvariantCulture);
    }
}

Um eine korrekte Zeichenfolge für die aktuelle Kultur zu erstellen, verwenden Sie einfach den Ausdruck:

Culture.Current($"interpolated {typeof(string).Name} string.")
Culture.Invariant($"interpolated {typeof(string).Name} string.")
Hinweis : Current und Invariant können nicht als Erweiterungsmethoden erstellt werden, da der Compiler dem interpolierten Zeichenfolgenausdruck standardmäßig den Typ String zuweist, wodurch der folgende Code nicht kompiliert werden kann:

$"interpolated {typeof(string).Name} string.".Current();

FormattableString Klasse enthält bereits die Invariant() -Methode. Die einfachste Möglichkeit, zur invarianten Kultur zu wechseln, ist die using static :

using static System.FormattableString;

string invariant = Invariant($"Now = {DateTime.Now}"); string current = $"Now = {DateTime.Now}";


Hinter den Kulissen

Interpolierte Zeichenfolgen sind nur ein syntaktischer Zucker für String.Format() . Der Compiler ( Roslyn ) verwandelt es hinter den Kulissen in ein String.Format :

var text = $"Hello {name + lastName}";

Das obige wird in etwa so konvertiert:

string text = string.Format("Hello {0}", new object[] {
    name + lastName
});

String Interpolation und Linq

In Linq-Anweisungen können interpolierte Zeichenfolgen verwendet werden, um die Lesbarkeit weiter zu verbessern.

var fooBar = (from DataRow x in fooBarTable.Rows
          select string.Format("{0}{1}", x["foo"], x["bar"])).ToList();

Kann umgeschrieben werden als:

var fooBar = (from DataRow x in fooBarTable.Rows
          select $"{x["foo"]}{x["bar"]}").ToList();

Wiederverwendbare interpolierte Zeichenketten

Mit string.Format können Sie wiederverwendbare string.Format erstellen:

public const string ErrorFormat = "Exception caught:\r\n{0}";

// ...

Logger.Log(string.Format(ErrorFormat, ex));

Interpolierte Zeichenfolgen werden jedoch nicht mit Platzhaltern kompiliert, die sich auf nicht vorhandene Variablen beziehen. Folgendes wird nicht kompiliert:

public const string ErrorFormat = $"Exception caught:\r\n{error}";
// CS0103: The name 'error' does not exist in the current context

Erstellen Func<> stattdessen eine Func<> die Variablen verwendet und einen String zurückgibt:

public static Func<Exception, string> FormatError =
    error => $"Exception caught:\r\n{error}";

// ...

Logger.Log(FormatError(ex));

String Interpolation und Lokalisierung

Wenn Sie Ihre Anwendung lokalisieren, fragen Sie sich möglicherweise, ob Sie die String-Interpolation zusammen mit der Lokalisierung verwenden können. Tatsächlich wäre es schön, die Möglichkeit , in Ressource zu speichern, zu müssen Dateien String s wie:

"My name is {name} {middlename} {surname}"
statt der viel weniger lesbaren:

"My name is {0} {1} {2}"

String Interpolationsprozess findet zur Kompilierungszeit statt , im Gegensatz zur Formatierungszeichenfolge mit string.Format die zur Laufzeit erfolgt . Ausdrücke in einer interpolierten Zeichenfolge müssen auf Namen im aktuellen Kontext verweisen und müssen in Ressourcendateien gespeichert werden. Das bedeutet, wenn Sie die Lokalisierung verwenden möchten, müssen Sie Folgendes tun:

var FirstName = "John";

// method using different resource file "strings"
// for French ("strings.fr.resx"), German ("strings.de.resx"), 
// and English ("strings.en.resx")
void ShowMyNameLocalized(string name, string middlename = "", string surname = "")
{
    // get localized string
    var localizedMyNameIs = Properties.strings.Hello;
    // insert spaces where necessary
    name = (string.IsNullOrWhiteSpace(name) ? "" : name + " ");
    middlename = (string.IsNullOrWhiteSpace(middlename) ? "" : middlename + " ");
    surname = (string.IsNullOrWhiteSpace(surname) ? "" : surname + " ");
    // display it
    Console.WriteLine($"{localizedMyNameIs} {name}{middlename}{surname}".Trim());
}

// switch to French and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
ShowMyNameLocalized(FirstName);

// switch to German and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
ShowMyNameLocalized(FirstName);

// switch to US English and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
ShowMyNameLocalized(FirstName);

Wenn die Ressourcenzeichenfolgen für die oben verwendeten Sprachen korrekt in den einzelnen Ressourcendateien gespeichert sind, sollten Sie die folgende Ausgabe erhalten:

Bonjour, mon nom est John
Hallo, mein Name ist John
Hallo mein Name ist John

Beachten Sie, dass dies bedeutet, dass der Name in jeder Sprache der lokalisierten Zeichenfolge folgt. Ist dies nicht der Fall, müssen Sie den Ressourcenzeichenfolgen Platzhalter hinzufügen und die obige Funktion ändern oder die Kulturinformationen in der Funktion abfragen und eine switch case-Anweisung angeben, die die verschiedenen Fälle enthält. Weitere Informationen zu Ressourcendateien finden Sie unter So verwenden Sie die Lokalisierung in C # .

Es empfiehlt sich, eine Standard-Ausweichsprache zu verwenden, die die meisten Leute verstehen, falls keine Übersetzung verfügbar ist. Ich schlage vor, Englisch als Standard-Ausweichsprache zu verwenden.

Rekursive Interpolation

Obwohl es nicht sehr nützlich ist, darf eine interpolierte string rekursiv in den geschweiften Klammern eines anderen verwendet werden:

Console.WriteLine($"String has {$"My class is called {nameof(MyClass)}.".Length} chars:");
Console.WriteLine($"My class is called {nameof(MyClass)}.");

Ausgabe:

String hat 27 Zeichen:

Meine Klasse heißt MyClass.