C#
String.Format
string concatenation
programming best practices
.NET

When is it better to use String.Format vs string concatenation?

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

In C#, you have three main ways to build strings: concatenation with +, String.Format(), and string interpolation ($""). String concatenation is simplest for combining 2-3 values. String.Format is better for localization and reusable format templates. String interpolation (C# 6+) combines readability with performance and is the preferred choice for most modern C# code. Performance differences are negligible in most cases — readability and maintainability should drive the decision.

String Concatenation (+ Operator)

csharp
1string firstName = "Alice";
2string lastName = "Smith";
3int age = 30;
4
5// Simple concatenation
6string result = "Name: " + firstName + " " + lastName + ", Age: " + age;
7// "Name: Alice Smith, Age: 30"

The compiler optimizes adjacent string concatenations into a single String.Concat() call:

csharp
1// The compiler transforms this:
2string s = "Hello" + " " + name + "!";
3
4// Into this:
5string s = String.Concat("Hello ", name, "!");

When Concatenation Works Well

csharp
// 2-3 values — clear and simple
string fullName = firstName + " " + lastName;
string path = directory + "/" + filename;

When Concatenation Becomes Unreadable

csharp
1// Hard to read — too many + operators and mixed types
2string sql = "SELECT " + columns + " FROM " + table
3    + " WHERE " + condition + " ORDER BY " + orderBy
4    + " LIMIT " + limit.ToString();

String.Format()

csharp
1string result = String.Format("Name: {0} {1}, Age: {2}", firstName, lastName, age);
2// "Name: Alice Smith, Age: 30"
3
4// Numbered placeholders can reuse arguments
5string repeated = String.Format("{0} said: '{1}'. Yes, {0} really said '{1}'.",
6    "Alice", "Hello");
7// "Alice said: 'Hello'. Yes, Alice really said 'Hello'."

Format Specifiers

String.Format supports rich formatting that concatenation cannot do inline:

csharp
1double price = 1234.5;
2DateTime now = DateTime.Now;
3
4// Currency formatting
5String.Format("Price: {0:C}", price);        // "Price: $1,234.50"
6
7// Number formatting
8String.Format("Count: {0:N0}", 1000000);     // "Count: 1,000,000"
9String.Format("Percent: {0:P1}", 0.856);     // "Percent: 85.6%"
10
11// Date formatting
12String.Format("Date: {0:yyyy-MM-dd}", now);  // "Date: 2025-03-02"
13String.Format("Time: {0:HH:mm:ss}", now);    // "Time: 14:30:00"
14
15// Padding and alignment
16String.Format("{0,-20} {1,10:C}", "Widget", 9.99);
17// "Widget                   $9.99"

Localization

String.Format works with resource files for localization:

csharp
1// Resources.resx (English): WelcomeMessage = "Hello {0}, you have {1} items"
2// Resources.resx (French): WelcomeMessage = "Bonjour {0}, vous avez {1} articles"
3
4string message = String.Format(Resources.WelcomeMessage, userName, itemCount);
5// The template changes by locale, but the code stays the same

Concatenation cannot do this because the argument order is baked into the code.

String Interpolation ($"") — Preferred in Modern C#

csharp
1// C# 6+ — string interpolation
2string result = $"Name: {firstName} {lastName}, Age: {age}";
3
4// Expressions inside braces
5string info = $"Name: {firstName.ToUpper()}, Born: {2025 - age}";
6
7// Format specifiers work too
8double price = 1234.5;
9string formatted = $"Price: {price:C}";        // "Price: $1,234.50"
10string padded = $"{"Item",-20} {price,10:C}";  // Alignment works

C# 10+ Improvements

csharp
1// C# 10: interpolated strings can be const
2const string greeting = $"Hello, World!";
3
4// C# 10: interpolated string handlers — no allocation for logging
5logger.LogDebug($"Processing order {orderId} for {customerName}");
6// The interpolation is only evaluated if debug logging is enabled

Performance Comparison

csharp
1// For most code, performance differences are negligible
2// Here is the hierarchy for large-scale string building:
3
4// 1. StringBuilder — best for loops
5var sb = new StringBuilder();
6for (int i = 0; i < 10000; i++)
7    sb.Append($"Item {i}, ");
8
9// 2. String interpolation / String.Format — same performance, both use
10//    String.Format internally (in C# 6-9) or handlers (C# 10+)
11string s1 = $"Hello {name}";
12string s2 = String.Format("Hello {0}", name);
13
14// 3. Concatenation — fine for 2-4 values, poor in loops
15string s3 = "Hello " + name;
csharp
1// NEVER concatenate in a loop
2string result = "";
3for (int i = 0; i < 10000; i++)
4    result += i.ToString();  // Creates 10,000 intermediate strings — O(n²)
5
6// USE StringBuilder instead
7var sb = new StringBuilder();
8for (int i = 0; i < 10000; i++)
9    sb.Append(i);
10string result = sb.ToString();  // O(n)

When to Use Each

ScenarioBest ChoiceWhy
Simple 2-3 value joinConcatenation or interpolationReadable, no overhead
Formatted numbers/datesInterpolation with format specifiers$"{price:C}" is clean
Localized messagesString.Format with resource templatesTemplate from resource file
Reusable format templateString.FormatTemplate stored as variable
Building strings in a loopStringBuilderAvoids O(n²) allocation
Logging (C# 10+)InterpolationHandler avoids allocation if log level disabled
SQL/HTML templatesNeither — use parameterized queries/templatesPrevents injection

Common Pitfalls

  • Concatenation in loops: Each += creates a new string object and copies all previous characters. This is O(n²) for n iterations. Use StringBuilder for any loop that builds a string incrementally.
  • Wrong placeholder index in String.Format: String.Format("{0} {2}", a, b) throws FormatException at runtime because {2} requires a third argument. String interpolation avoids this entirely since values are inline.
  • Using string building for SQL/HTML: Never build SQL queries or HTML with concatenation, String.Format, or interpolation. This creates injection vulnerabilities. Use parameterized queries for SQL and template engines for HTML.
  • Premature optimization: The performance difference between concatenation, String.Format, and interpolation for a few values is nanoseconds. Choose based on readability. Only optimize string building in hot loops or when profiling shows it matters.
  • Forgetting StringBuilder.ToString(): StringBuilder does not implicitly convert to string. You must call .ToString() to get the final string. Passing a StringBuilder where a string is expected causes a compile error or calls Object.ToString() which gives the type name.

Summary

  • Use string interpolation ($"") as the default in modern C# — readable and performant
  • Use String.Format when the format template comes from a resource file (localization) or is stored as a variable
  • Use concatenation only for trivially simple joins of 2-3 values
  • Use StringBuilder for building strings in loops — never concatenate with += in a loop
  • Format specifiers ({0:C}, {0:N2}, {0:yyyy-MM-dd}) work in both String.Format and interpolation
  • Performance is almost never the deciding factor — choose for readability

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms