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

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

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

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 illustration
Course illustration

All Rights Reserved.