Question

How to Escape Curly Braces in C# String.Format

csharp.netstring

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.

Take Quiz

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} inserts 42
  • {1} inserts Ava
  • }} 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:

  1. String.Format reads the format string.
  2. It sees {0} and replaces it with the first value: "Int32".
  3. It sees {1} and replaces it with the second value: "MyProperty".
  4. It sees {{ and converts it to a literal {.
  5. It keeps the text get; private set; as normal text.
  6. It sees }} and converts it to a literal }.
  7. 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} becomes 10
  • }} 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.

Take Quiz

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.Format to 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.Format treats { 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

ApproachExampleBest forNotes
String.FormatString.Format("Hello {0}", name)Older code, indexed placeholdersLiteral braces must be doubled
String interpolation$"Hello {name}"Modern C# codeUsually easier to read; literal braces still doubled
String concatenation"Hello " + nameVery simple casesHarder to read for complex strings
Verbatim strings@"C:\Temp"Paths and multiline textDoes 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
Take Quiz

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.

Take Quiz

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.Format to insert the type and name.
  • Output literal { and } characters correctly.
  • Print the generated lines to the console.
Take Quiz

Keep learning

Related questions

View more