Question
How can I display a literal curly brace character when using String.Format in C#?
For example, consider this code:
sb.AppendLine(String.Format(
"public {0} {1} { get; private set; }",
prop.Type,
prop.Name
));
I want the generated output to be:
public Int32 MyProperty { get; private set; }
What is the correct way to include literal { and } characters in a String.Format format string?
Short Answer
By the end of this page, you will understand why curly braces have special meaning in C# String.Format, how to escape them correctly, and how to safely generate strings that contain both placeholders and literal braces.
Concept
In C#, String.Format uses curly braces to mark placeholders.
A placeholder looks like this:
{0}
{1}
{2}
These placeholders tell String.Format where to insert values.
For example:
string result = String.Format("Hello, {0}!", "Sam");
// result = "Hello, Sam!"
Because braces are part of the formatting syntax, writing a single { or } directly in the format string is not treated as normal text. Instead, String.Format tries to interpret it as part of a placeholder.
That is why this causes a problem:
String.Format("public {0} {1} { get; private set; }", prop.Type, prop.Name)
The braces around get; private set; are read as formatting syntax, not as literal characters.
The rule
To output a literal brace in String.Format, you must double it:
{{outputs{}}outputs}
So the correct version is:
String.Format("public {0} {1} {{ get; private set; }}", prop.Type, prop.Name)
This matters in real programming because formatted strings are often used to generate:
- source code
- JSON-like text
- log messages
- templates
- configuration files
Whenever the output itself needs braces, you must escape them correctly.
Mental Model
Think of String.Format like a template machine.
- Single braces mean: "insert something here"
- Double braces mean: "print an actual brace character"
So:
"Name: {0}"
means:
- find placeholder
0 - insert the first value
But:
"{{ Hello }}"
means:
{{becomes{}}becomes}- final output is
{ Hello }
A simple analogy: placeholders are like special command markers. If you want to print the marker itself, you must escape it by doubling it.
Syntax and Examples
The basic syntax of String.Format is:
String.Format("text {0} more text {1}", value1, value2)
Escaping braces
Use doubled braces for literal output:
String.Format("{{0}}")
Output:
{0}
Your example
string result = String.Format(
"public {0} {1} {{ get; private set; }}",
"Int32",
"MyProperty"
);
Console.WriteLine(result);
Output:
public Int32 MyProperty { get; private set; }
Another example
string message = String.Format("User {{ ID: {0}, Name: {1} }}", 42, "Ava");
Console.WriteLine(message);
Output:
User { ID: 42, Name: Ava }
In this example:
{{prints{{0}inserts42{1}insertsAva}}prints}
Step by Step Execution
Consider this code:
string text = String.Format("public {0} {1} {{ get; private set; }}", "Int32", "MyProperty");
Here is what happens step by step:
String.Formatreads the format string.- It sees
{0}and replaces it with the first value:"Int32". - It sees
{1}and replaces it with the second value:"MyProperty". - It sees
{{and converts it to a literal{. - It keeps the text
get; private set;as normal text. - It sees
}}and converts it to a literal}. - The final result becomes:
public Int32 MyProperty { get; private set; }
Small trace example
string s = String.Format("Value: {{ {0} }}", 10);
Processing:
Value:stays the same{{becomes{{0}becomes10}}becomes}
Final output:
Value: { 10 }
Real World Use Cases
Escaping braces in String.Format is useful whenever your output contains text with {} characters.
1. Generating C# code
string code = String.Format(
"public {0} {1} {{ get; set; }}",
"string",
"Name"
);
Useful for code generators, scaffolding tools, or templates.
2. Creating structured log messages
string log = String.Format("Request {{ Id: {0}, Status: {1} }}", 123, "OK");
Useful when you want readable logs with grouped values.
3. Building JSON-like or config-like output
string jsonLike = String.Format("{{ \"id\": {0}, \"name\": \"{1}\" }}", 1, "Alice");
Even if you should use a serializer for real JSON, this still helps explain the formatting rule.
4. Template generation
string template = String.Format("function {0}() {{ return true; }}", "isReady");
Useful when generating JavaScript, CSS, or other text-based files.
Real Codebase Usage
In real projects, developers often use brace escaping in these situations:
Code generation
Applications that generate classes, properties, methods, or configuration files frequently build strings containing braces.
var line = String.Format("public {0} {1} {{ get; set; }}", typeName, propertyName);
Logging and diagnostics
When output format matters, developers may build readable strings with labeled values.
var msg = String.Format("Order {{ Id: {0}, Total: {1} }}", order.Id, order.Total);
Guarding against formatting errors
If a string contains braces that are not placeholders, developers escape them early to avoid runtime exceptions.
Common patterns in real code
- Template strings for generated files
- Validation output that wraps values in braces for clarity
- Error handling where formatted messages include structured text
- Early refactoring from
String.Formatto interpolation when readability improves
For newer C# code, many developers prefer string interpolation for readability:
$"public {prop.Type} {prop.Name} {{ get; private set; }}"
But the same brace escaping rule still applies: literal braces must still be doubled.
Common Mistakes
1. Using single braces for literal output
Broken code:
String.Format("public {0} {1} { get; private set; }", "Int32", "MyProperty")
Why it fails:
String.Formattreats{ get; private set; }as formatting syntax.- This leads to a format error.
Fix:
String.Format("public {0} {1} {{ get; private set; }}", "Int32", "MyProperty")
2. Escaping only one side
Broken code:
String.Format("Value: {{ {0} }", 10)
Why it fails:
- Opening brace is escaped correctly.
- Closing brace is not.
Fix:
String.Format("Value: {{ {0} }}", 10)
3. Forgetting that placeholders also use braces
Broken code:
String.Format("{0} {{1}}", "A", "B")
Output:
A {1}
Why this happens:
{{1}}prints{1}literally.- It does not use placeholder
1.
If you want both placeholders replaced, write:
String.Format("{0} {1}", "A", "B")
4. Building JSON manually when a serializer is better
This is not always wrong, but it is error-prone:
String.Format("{{ \"name\": \"{0}\" }}", name)
For real JSON, prefer a serializer such as System.Text.Json when possible.
5. Assuming string interpolation removes the rule
Even with interpolation, literal braces still need doubling:
$"public {prop.Type} {prop.Name} {{ get; private set; }}"
Comparisons
| Approach | Example | Best for | Notes |
|---|---|---|---|
String.Format | String.Format("Hello {0}", name) | Older code, indexed placeholders | Literal braces must be doubled |
| String interpolation | $"Hello {name}" | Modern C# code | Usually easier to read; literal braces still doubled |
| String concatenation | "Hello " + name | Very simple cases | Harder to read for complex strings |
| Verbatim strings | @"C:\Temp" | Paths and multiline text | Does not change String.Format brace rules |
String.Format vs string interpolation
String.Format("public {0} {1} {{ get; set; }}", type, name)
$"public {type} {name} {{ get; set; }}"
Interpolation is often easier to read because names are used directly instead of numeric indexes.
Important note
Whether you use String.Format or interpolation:
- placeholders use braces
- literal braces must be escaped
Cheat Sheet
Quick rule
In C# format strings:
{{=>{}}=>}
Placeholder syntax
String.Format("{0}", value)
String.Format("{0} {1}", first, second)
Literal brace examples
String.Format("{{") // "{"
String.Format("}}") // "}"
String.Format("{{0}}") // "{0}"
Combined example
String.Format("public {0} {1} {{ get; set; }}", "int", "Age")
Output:
public int Age { get; set; }
Common error
String.Format("{ hello }")
This is invalid because single braces are interpreted as format syntax.
Modern alternative
$"public {type} {name} {{ get; set; }}"
Still uses doubled braces for literal { and }.
FAQ
How do you escape curly braces in C# String.Format?
Use doubled braces:
{{for{}}for}
Why does String.Format treat braces specially?
Because braces define placeholders such as {0} and {1} where values are inserted.
Can I use backslashes to escape braces in C# format strings?
No. In String.Format, braces are escaped by doubling them, not with backslashes.
Does string interpolation also require escaped braces?
Yes. In interpolated strings, literal braces must also be written as {{ and }}.
What exception happens if braces are not escaped correctly?
You typically get a FormatException because the format string is invalid.
Is String.Format still used in modern C#?
Yes, especially in older codebases or APIs that expect format strings. However, string interpolation is often more readable in new code.
Should I build JSON with String.Format?
For simple examples, you can. In production code, a JSON serializer is usually safer and easier to maintain.
Mini Project
Description
Build a small C# program that generates property declarations as strings. This demonstrates how String.Format works when placeholders and literal braces appear in the same output.
Goal
Create a program that prints multiple valid C# property declarations using escaped braces in String.Format.
Requirements
- Create a class or simple data structure to hold a property type and name.
- Generate at least three property declaration lines.
- Use
String.Formatto insert the type and name. - Output literal
{and}characters correctly. - Print the generated lines to the console.
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.