String Concatenation - Combining Strings Effectively in C#

Vaibhav • September 10, 2025

Concatenation is the act of joining two or more strings to form a new one. You’ll do this constantly: building log messages, generating prompts, composing file paths, assembling CSV lines, and creating UI text. In this article, we’ll go deeper than “use the + operator.” You’ll learn when to use each of the main techniques-+, string.Concat, string.Join, string interpolation ($""), and StringBuilder-with practical guidance, step‑by‑step examples, and performance‑minded best practices that stay within Chapter 8’s boundaries.

Strings are immutable. Every concatenation creates a new string instance. That’s fine in small amounts, but for repeated or large concatenations, you’ll want the right tool (usually StringBuilder or string.Join) to avoid unnecessary allocations.

1) The + operator - simplest and very readable

The + operator is the most direct way to join a handful of strings. It’s perfect when you’re assembling short messages from a few parts.

string first = "Hello";
string second = "World";
string combined = first + " " + second + "!"; // "Hello World!"

Step-by-step:

  • first + " " creates a new string containing "Hello ".
  • Concatenating second yields "Hello World".
  • Adding "!" produces the final "Hello World!".

For few joins, this is both expressive and fast enough. The C# compiler also performs constant folding for string literals, so something like "A" + "B" + "C" becomes a single literal at compile time (no runtime overhead).

The + operator respects evaluation order and operator precedence just like arithmetic. Parenthesize complex expressions for clarity when mixing numbers and strings.

2) string.Concat - many overloads, explicit intent

string.Concat provides multiple overloads for joining two, three, four strings, or even an enumerable. It expresses intent (“we are concatenating pieces”) and can be a touch clearer in APIs and utility methods.

// Basic overloads
string merged2 = string.Concat("A", "B");         // "AB"
string merged3 = string.Concat("A", "B", "C");    // "ABC"
string merged4 = string.Concat("A", "B", "C", "D"); // "ABCD"

// Concatenate an array
string[] parts = { "root", "/", "sub", "/", "file.txt" };
string path = string.Concat(parts); // "root/sub/file.txt"

When to use: prefer string.Concat when you already have an array of small parts or you want a method call that reads semantically (“concat these”). It’s functionally similar to + for a few items, but scales better when you start from a collection of strings.

3) string.Join - best for lists with separators

If you need a separator (comma, space, newline), string.Join is the go‑to. It accepts any IEnumerable<string> (like arrays or List<string>) and inserts the separator between elements.

var names = new List<string> { "Ada", "Grace", "Linus" };
string csv = string.Join(",", names);         // "Ada,Grace,Linus"
string spaced = string.Join(" ", names);      // "Ada Grace Linus"
string lines = string.Join(Environment.NewLine, names);
// "Ada\nGrace\nLinus" (platform-specific newline)

Why it’s great: you won’t forget commas or extra spaces; you get predictable separators; it’s efficient for joining many elements because it computes the final length and builds once, instead of allocating per piece.

Any time you find yourself appending a separator inside a loop and trimming the last one afterward, replace that pattern with string.Join.

4) String interpolation $"" - clear, modern, and safe

Interpolation allows you to embed expressions inside { } placeholders. It’s usually the most readable way to build a sentence‑like string.

string user = "Vaibhav";
int count = 3;
string line = $"Hello {user}, you have {count} new messages.";
// "Hello Vaibhav, you have 3 new messages."

Formatting inside placeholders:

double price = 1234.5;
DateTime now = DateTime.Now;

string receipt = $"Total: {price:F2} INR, Date: {now:yyyy-MM-dd}";
// e.g., "Total: 1234.50 INR, Date: 2025-09-10"

Interpolation reduces mistakes (missing spaces or separators) and keeps code intent front‑and‑center. Prefer it over + when you construct sentences, log lines, or any message with mixed values and labels.

Interpolation compiles down to concatenation operations. For short strings, performance is similar to +, but interpolation is almost always clearer to read.

5) StringBuilder - the right tool for loops and large outputs

Because strings are immutable, repeatedly concatenating inside loops can generate many temporary objects. StringBuilder is mutable and designed for such scenarios.

var sb = new StringBuilder(capacity: 256); // optional capacity hint
for (int i = 1; i <= 5; i++)
{
    sb.Append("Item ");
    sb.Append(i);
    sb.AppendLine();
}
string result = sb.ToString();
/*
Item 1
Item 2
Item 3
Item 4
Item 5
*/

Step-by-step: each Append mutates the builder’s internal buffer. Only ToString() produces the final immutable string. The optional capacity helps avoid internal resizing if you can estimate the final length.

Use StringBuilder when:
1) concatenating in loops, 2) building large documents (e.g., multi‑line reports), or 3) you can pre‑estimate the final size and benefit from a capacity hint.

6) Concatenation with non-strings (numbers, dates, chars)

Concatenating a non‑string automatically calls its ToString(). That’s convenient, but you often want control over formatting (e.g., decimal places or dates).

int age = 30;
DateTime today = new DateTime(2025, 9, 10);

string s1 = "Age: " + age;                       // "Age: 30"
string s2 = $"Today is {today:dd-MMM-yyyy}";     // "Today is 10-Sep-2025"
char sep = ':';
string s3 = "Key" + sep + "Value";               // "Key:Value"

Tip: prefer interpolation with format specifiers for clarity and control.

7) Choosing newlines and separators intentionally

When building multi‑line strings, choose a platform‑appropriate newline via Environment.NewLine, and consider string.Join(Environment.NewLine, ...) for lists of lines.

var lines = new List<string> { "alpha", "beta", "gamma" };
string block = string.Join(Environment.NewLine, lines);
/*
alpha
beta
gamma
*/

This avoids hardcoding "\n" or "\r\n", making your output portable and predictable.

8) File paths and URLs - don’t concatenate blindly

While this chapter is about strings, a practical warning helps: concatenating path pieces with "/" or "\\\\" is error‑prone. Use APIs designed for composition (e.g., Path.Combine) when you reach the File I/O chapter. For now, know that many “concatenation bugs” are actually “wrong kind of join” problems.

Similarly for URLs, prefer a URI/URL builder (later chapters) over raw string concatenation to avoid missing slashes or double separators.

9) Performance considerations (practical, not premature)

For a few strings, + or interpolation is fine and clearest. For many parts or loops, use StringBuilder or string.Join. Keep these rules of thumb:

  • Small, fixed sentences: interpolation ($"") or +
  • Lots of parts with separators: string.Join
  • Looped construction / large output: StringBuilder (with capacity if possible)
  • Already have an array of parts without a separator: string.Concat

Even when using +, the JIT and runtime are quite optimized for short strings. Readability comes first-only switch techniques when size or repetition demands it.

10) Avoiding common pitfalls

  • Forgetting spaces: "Hello" + name yields "HelloVaibhav". Prefer interpolation to make spaces obvious: $"Hello {name}".
  • Trailing separators in loops: Appending "," then trimming later is fragile. Use string.Join.
  • Concatenating in tight loops: Switch to StringBuilder to avoid lots of temporary strings.
  • Culture‑sensitive text: When concatenating numbers/dates for user‑facing text, prefer interpolation with format strings so the output is explicit and readable.

11) Practical mini‑projects with concatenation

11.1) Building a CSV line

var fields = new List<string> { "Ada", "Lovelace", "Mathematician" };
string csvLine = string.Join(",", fields); // "Ada,Lovelace,Mathematician"

Why this works well: predictable separators, no off‑by‑one commas.

11.2) Constructing a multi‑line message

var sb = new StringBuilder();
sb.AppendLine("Report");
sb.AppendLine("------");
sb.AppendLine($"Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
string report = sb.ToString();

Why this works well: StringBuilder excels for multi‑line assembly and future growth.

11.3) Logging with interpolation

string user = "Vaibhav";
int attempts = 2;
Console.WriteLine($"User '{user}' failed login {attempts} time(s).");

Why this works well: easy to read, easy to maintain, no missing spaces.

12) Decision checklist (quick reference)

  • Is it a short, sentence‑like message? → Interpolation
  • Do you have many items with a separator? → string.Join
  • Are you appending inside a loop or building a large block? → StringBuilder
  • Do you already have an array (no separator)? → string.Concat
  • Just a couple values? → + or interpolation (whichever reads clearer)

Summary

Concatenation is simple, but the approach you choose affects clarity, correctness, and performance. Use interpolation for readable, sentence‑like strings. Use string.Join for lists with separators. Use StringBuilder for loops and large outputs-add a capacity hint when you can. Reach for string.Concat when you already have an array of parts and no separator is needed. Keep newlines and separators intentional, avoid trailing separator hacks, and choose formatting explicitly for numbers and dates. With these patterns, you’ll write string code that’s concise, robust, and efficient.