Question
In .NET, how can curly braces be escaped when using string.Format?
For example:
string val = "1,2,3";
string result = string.Format(" foo {{0}}", val);
This code does not throw an exception, but it outputs:
foo {0}
How do format strings treat curly braces, and how can you include literal braces while still formatting values correctly?
Short Answer
By the end of this page, you will understand how .NET composite formatting works, why curly braces have special meaning in string.Format, and how to output literal { and } characters by escaping them correctly with doubled braces.
Concept
In .NET, string.Format uses composite formatting. Inside the format string, curly braces define placeholders where values should be inserted.
A placeholder looks like this:
"{0}"
Here, 0 means: use the first argument passed after the format string.
For example:
string name = "Alice";
string message = string.Format("Hello, {0}", name);
// Hello, Alice
Curly braces are therefore not treated as normal characters. They are part of the formatting syntax.
To include a literal brace in the output, you must escape it by doubling it:
{{outputs{}}outputs}
Example:
string result = string.Format("Value: {{ {0} }}", 42);
// Value: { 42 }
This matters because many real programs generate text with braces, such as:
- JSON-like snippets
- template output
- log messages
- configuration text
- code generation
If you forget that braces have special meaning in format strings, you may get incorrect output or a FormatException.
Mental Model
Think of a format string as a sentence with instruction markers.
{0}means: "insert the first value here"{1}means: "insert the second value here"{{means: "I really want a literal{character"}}means: "I really want a literal}character"
So braces have two possible roles:
- Formatting commands like
{0} - Literal characters when escaped as
{{and}}
It is similar to using a reserved symbol in a programming language. Because { and } already mean something special, you must explicitly tell .NET when you want them printed as plain text.
Syntax and Examples
The basic syntax of string.Format is:
string.Format("text {0} more text", value0);
Insert a value
string name = "Sam";
string result = string.Format("Hello, {0}", name);
// Hello, Sam
Output literal braces
string result = string.Format("{{Hello}}") ;
// {Hello}
Output braces around a formatted value
string val = "1,2,3";
string result = string.Format("foo {{{0}}}", val);
// foo {1,2,3}
Why this works
{{becomes a literal{{0}inserts the first argument, which isval}}becomes a literal}
So this format string:
"foo {{{0}}}"
is interpreted as:
- print
foo - print
{ - insert argument
0 - print
}
Multiple placeholders
string first = "A";
string second = "B";
string result = string.Format("Items: {{ {0}, {1} }}", first, second);
// Items: { A, B }
Using interpolation in modern C#
If you are using string interpolation, braces still need escaping the same way:
string val = "1,2,3";
string result = $"foo {{{val}}}";
// foo {1,2,3}
The rule is the same: doubled braces produce literal braces.
Step by Step Execution
Consider this example:
string val = "1,2,3";
string result = string.Format("foo {{{0}}}", val);
Here is what happens step by step:
valis assigned the string"1,2,3"..NETreads the format string:"foo {{{0}}}".- It sees
fooand copies that directly to the output. - It sees
{{and treats it as a literal{. - It sees
{0}and replaces it with the first argument after the format string, which isval. - It sees
}}and treats it as a literal}. - The final result becomes:
foo {1,2,3}
Now compare that with this code:
string result = string.Format("foo {{0}}", val);
Step by step:
foois copied as normal text.{{becomes a literal{.0is just the character0because it is no longer inside a formatting placeholder.}}becomes a literal}.- Final output:
foo {0}
That is why your original example prints {0} literally instead of substituting the value.
Real World Use Cases
Escaping braces in format strings is useful whenever you need both:
- formatted values, and
- literal brace characters in the output
Common scenarios
Logging structured-looking messages
string user = "alice";
string log = string.Format("User data: {{ Name: {0} }}", user);
// User data: { Name: alice }
Building JSON-like text manually
string id = "123";
string jsonLike = string.Format("{{ \"id\": \"{0}\" }}", id);
// { "id": "123" }
In real applications, use a JSON serializer instead of manually building JSON when possible.
Generating templates or code snippets
string methodName = "Print";
string code = string.Format("public void {0}() {{ }}", methodName);
// public void Print() { }
Displaying placeholder examples to users
string text = string.Format("Use the token {{username}} to insert the user name.");
// Use the token {username} to insert the user name.
Real Codebase Usage
In real codebases, developers often combine formatting with readability and safety.
Common patterns
1. Wrapping values in visible delimiters
string env = "prod";
string message = string.Format("Running in {{ {0} }} environment", env);
This is useful in logs or debugging output.
2. Building messages with named-looking tokens
string tokenHelp = string.Format("Available token: {{orderId}}");
This is common in email templates, configuration systems, or documentation text.
3. Guarding against malformed format strings
If the string contains unbalanced braces, .NET can throw FormatException.
try
{
string message = string.Format("Value: {0", 10);
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
4. Preferring interpolation for readability
In modern C#, developers often use string interpolation instead of string.Format for simple cases:
string val = "1,2,3";
string result = $"foo {{{val}}}";
This is easier to read than numbered placeholders.
5. Avoiding manual string construction for structured formats
If you are producing JSON, XML, or SQL, developers usually avoid hand-built strings when tools exist:
- use serializers for JSON/XML
- use parameters for SQL
- use templates for larger text generation
Escaped braces are useful, but they should not replace safer abstractions.
Common Mistakes
1. Escaping the placeholder itself by accident
Broken code:
string val = "1,2,3";
string result = string.Format("foo {{0}}", val);
// foo {0}
Why it happens:
{{and}}escape the braces- so
{0}never becomes a placeholder
Correct code:
string result = string.Format("foo {{{0}}}", val);
// foo {1,2,3}
2. Forgetting to escape literal braces
Broken code:
string result = string.Format("foo { {0} }", 10);
This may throw a FormatException because the braces are not valid formatting syntax.
Correct code:
string result = string.Format("foo {{ {0} }}", 10);
// foo { 10 }
3. Mismatching placeholder indexes
Broken code:
string result = string.Format("{1}", "only one value");
This can throw an exception because argument index 1 does not exist.
Correct code:
string result = string.Format("{0}", "only one value");
4. Using string.Format when no formatting is needed
Unnecessary:
string text = string.Format("{{hello}}");
Simpler:
string text = "{hello}";
If there are no placeholders, plain string literals are often clearer.
5. Confusing string.Format with string interpolation
In interpolation, the syntax changes slightly:
string name = "Sam";
string result = $"Hello, {name}";
But literal braces still require doubling:
string result = $"{{Hello}}";
// {Hello}
Comparisons
| Concept | Syntax | Best for | Notes |
|---|---|---|---|
string.Format placeholder | "{0}" | Reusable format strings, older C# code | Uses numeric indexes |
| Literal brace in format string | "{{" or "}}" | Printing actual { or } | Must be doubled |
| String interpolation | $"{value}" | Most modern C# code | Easier to read |
| Literal brace in interpolation | $"{{" or $"}}" | Printing braces in interpolated strings | Same escaping rule |
| Plain string literal | "{text}" | When no formatting is needed | No escaping needed unless syntax requires it |
string.Format vs interpolation
string name = "Mia";
string a = string.Format("Hello, {0}", name);
string b = $"Hello, {name}";
Both produce the same result.
When to use string.Format
- when working with older code
- when a format string is stored separately
- when using APIs that expect composite formatting
When to use interpolation
- in most new C# code
- when readability matters
- when expressions are simple
Escaped braces in both styles
string name = "Mia";
string a = string.Format("{{{0}}}", name); // {Mia}
string b = $"{{{name}}}"; // {Mia}
Cheat Sheet
Quick rules
{0}= insert first argument{1}= insert second argument{{= literal{}}= literal}
Common examples
string.Format("{0}", 5); // 5
string.Format("{{0}}"); // {0}
string.Format("{{{0}}}", 5); // {5}
string.Format("{{ {0} }}", 5); // { 5 }
Remember
- If you escape the braces around
0, then0is treated as plain text. - To print braces around a formatted value, use:
"{{{0}}}"
Interpolation equivalents
$"{value}" // inserts value
$"{{value}}" // prints {value}
$"{{{value}}}" // prints value inside braces
Edge cases
- Unmatched braces can cause
FormatException - Wrong placeholder indexes can cause
FormatException - If no formatting is needed, use a normal string instead of
string.Format
FAQ
How do I print { and } in string.Format?
Use doubled braces:
"{{" // {
"}}" // }
Why does string.Format("{{0}}", value) print {0}?
Because {{ and }} escape the braces, so 0 is treated as regular text instead of a placeholder.
How do I output {value} with formatting in C#?
Use:
string.Format("{{{0}}}", value)
Does string interpolation use the same brace escaping rule?
Yes. In interpolated strings, literal braces are also escaped with doubled braces.
What exception happens if the format string is invalid?
Usually .NET throws a FormatException if the braces are malformed or placeholder indexes are wrong.
Should I use string.Format or $"..." in modern C#?
For most new code, string interpolation is easier to read. string.Format is still useful in older code and APIs based on composite formatting.
Can I write JSON manually with string.Format?
You can, but in real applications it is better to use a JSON serializer for correctness and safety.
Mini Project
Description
Build a small C# console program that prints user data inside literal curly braces using both string.Format and string interpolation. This helps you practice the difference between placeholders and escaped braces in realistic output.
Goal
Create a console app that displays formatted values wrapped in literal {} characters without causing formatting errors.
Requirements
- Create a string variable for a user name and an integer variable for an age.
- Print one message using
string.Formatwith the values inside literal braces. - Print a second message using string interpolation with the same output style.
- Add one example that prints the literal text
{0}without replacing it. - Ensure the program runs without throwing
FormatException.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.