Einleitung: Wenn der Code anfängt, sich zu "verbiegen"
\n\nStellen Sie sich vor: Sie programmieren in C# und müssen eine Nachricht wie Wert: {42} ausgeben. Sie verwenden String.Format("Wert: {0}", 42) – und erhalten das erwartete Ergebnis. Versuchen Sie nun, einfach {42} ohne Ersetzung auszugeben. Wenn Sie naiv schreiben:
string result = String.Format("{{42}}");\n\nErwarten Sie {42} zu sehen, aber stattdessen erhalten Sie einen Formatfehler oder eine leere Zeichenfolge. Kommt Ihnen das bekannt vor? Diese Frage ist eine der beliebtesten auf Stack Overflow mit tausenden Aufrufen. Und heute geben wir nicht nur die Antwort, sondern schauen unter die Haube von .NET, um zu verstehen, wie die Maskierung geschweifter Klammern in C# funktioniert. Los geht's!
Das Problem: Warum funktioniert {{ nicht wie in anderen Sprachen?
\n\nIn C# sind geschweifte Klammern {} Sonderzeichen in Formatierungszeichenfolgen. Sie geben an, wo ein Platzhalter für die Ersetzung eines Werts beginnt und endet. Beispielsweise bedeutet {0} "füge hier das erste Argument ein".
Aber was ist, wenn wir die geschweiften Klammern selbst als Text ausgeben müssen? In den meisten Sprachen (Python, Java) funktioniert die Maskierung durch Verdopplung: {{ ergibt {. In C# gilt dieselbe Logik, jedoch mit einem Haken: Zwei öffnende Klammern {{ werden zu einer {, aber nur, wenn sie nicht Teil eines gültigen Platzhalters sind.
Ein Beispiel aus der Praxis: Sie schreiben einen Code-Generator in C# und müssen die Zeichenfolge if (x > 0) { return x; } ausgeben. Wenn Sie einfach schreiben:
string template = "if (x > 0) { return x; }";\n\nInterpretiert der Compiler oder String.Format { return x; } als Formatierungsversuch und löst eine FormatException aus.
Die Lösung: Korrekte Maskierung geschweifter Klammern in C#
\n\nDer klassische Weg: String.Format und StringBuilder
\n\nDie Regel ist einfach: Um eine einzelne geschweifte Klammer auszugeben, schreiben Sie zwei hintereinander.
\n\n// Gibt aus: {Hello World}\nstring result = String.Format("{{Hello World}}");\nConsole.WriteLine(result); // {Hello World}\n\nEs gibt jedoch eine Nuance: Wenn Sie sowohl Platzhalter als auch maskierte Klammern gleichzeitig verwenden müssen, ist die Reihenfolge wichtig. Zuerst die Maskierung, dann die Ersetzung:
\n\nint value = 42;\n// Gibt aus: Wert {42} in geschweiften Klammern\nstring result = String.Format("Wert {{{0}}} in geschweiften Klammern", value);\nConsole.WriteLine(result); // Wert {42} in geschweiften Klammern\n\nAnalysieren wir das im Detail: {{{0}}} ist {{ (eine Klammer) + {0} (Platzhalter) + }} (eine Klammer). Ergebnis: {42}.
Zeichenfolgeninterpolation ($"...") – der moderne Ansatz
\n\nSeit C# 6 haben wir die Zeichenfolgeninterpolation. Hier funktioniert die Maskierung anders – ebenfalls durch Verdopplung der Klammern, jedoch ohne Platzhalter darin:
\n\nint value = 42;\n// Gibt aus: Wert {42} in geschweiften Klammern\nstring result = $"Wert {{{value}}} in geschweiften Klammern";\nConsole.WriteLine(result); // Wert {42} in geschweiften Klammern\n\nBeachten Sie: Bei der Interpolation ergibt {{ ein {, und {value} ist die Ersetzung. Alles funktioniert intuitiv, wenn Sie die Regel beachten: Zwei Klammern – eine Klammer.
Fortgeschrittener Fall: StringBuilder.AppendFormat
\n\nWenn Sie mit StringBuilder arbeiten, verwenden Sie dieselbe Syntax:
var sb = new StringBuilder();\nsb.AppendFormat("{{0}} = {0}", 123);\nConsole.WriteLine(sb.ToString()); // {0} = 123\n\nWie es unter der Haube funktioniert: Analyse des Formatierungsmechanismus
\n\nWerfen wir einen Blick in den .NET-Quellcode (er ist auf GitHub offen!). Wenn Sie String.Format aufrufen, wird intern die Methode FormatHelper gestartet, die die Zeichen der Formatzeichenfolge durchläuft.