Introduction: When the Code Starts to "Bend"
\n\nImagine: you're writing in C# and need to output a message like Value: {42}. You use String.Format("Value: {0}", 42) — and get the expected result. Now try to output just {42} without substitution. Naively writing:
string result = String.Format("{{42}}");\n\nYou expect to see {42}, but instead get a format error or an empty string. Sound familiar? This question is one of the most popular on Stack Overflow with thousands of views. And today we won't just give the answer, but will look under the hood of .NET to understand how escaping curly braces works in C#. Let's go!
The Problem: Why {{ Doesn't Work Like in Other Languages?
\n\nIn C#, curly braces {} are special characters in format strings. They indicate where a placeholder for value substitution begins and ends. For example, {0} means "insert the first argument here".
But what if we need to output the curly braces themselves as text? In most languages (Python, Java), escaping works by doubling: {{ gives {. In C#, the logic is the same, but with a twist: two opening braces {{ turn into one {, but only if they are not part of a valid placeholder.
A real-life example: you're writing a code generator in C# and need to output the string if (x > 0) { return x; }. If you simply write:
string template = "if (x > 0) { return x; }";\n\nThe compiler or String.Format will interpret { return x; } as an attempt at formatting and throw a FormatException.
The Solution: Properly Escaping Curly Braces in C#
\n\nThe Classic Way: String.Format and StringBuilder
\n\nThe rule is simple: to output one curly brace, write two in a row.
\n\n// Outputs: {Hello World}\nstring result = String.Format("{{Hello World}}");\nConsole.WriteLine(result); // {Hello World}\n\nBut there's a nuance: if you need to use both placeholders and escaped braces simultaneously, the order matters. First escaping, then substitution:
\n\nint value = 42;\n// Outputs: Value {42} in curly braces\nstring result = String.Format("Value {{{0}}} in curly braces", value);\nConsole.WriteLine(result); // Value {42} in curly braces\n\nLet's break it down: {{{0}}} is {{ (one brace) + {0} (placeholder) + }} (one brace). Result: {42}.
String Interpolation ($"...") — The Modern Approach
\n\nStarting with C# 6, we have string interpolation. Here, escaping works differently — through doubling the braces, but without placeholders inside:
\n\nint value = 42;\n// Outputs: Value {42} in curly braces\nstring result = $"Value {{{value}}} in curly braces";\nConsole.WriteLine(result); // Value {42} in curly braces\n\nNote: in interpolation, {{ gives {, and {value} is a substitution. Everything works intuitively if you remember the rule: two braces — one brace.
Advanced Case: StringBuilder.AppendFormat
\n\nWhen working with StringBuilder, use the same syntax:
var sb = new StringBuilder();\nsb.AppendFormat("{{0}} = {0}", 123);\nConsole.WriteLine(sb.ToString()); // {0} = 123\n\nHow It Works Under the Hood: Breakdown of the Formatting Mechanism
\n\nLet's look into the .NET source code (it's open on GitHub!). When you call String.Format, the FormatHelper method is invoked internally, which iterates through the characters of the format string.