Learning outcome
You should be able to choose text construction based on the shape of the work, not on a blanket rule like “always use StringBuilder.” For a fixed, small number of pieces, concatenation or interpolation is usually clearer. For many appends in a loop, especially when the final size is unknown, StringBuilder is the better fit. For collections, string.Join or string.Concat often expresses intent more directly than either manual concatenation or a builder.
Intuition
string is immutable: every time you combine text, a new string result must be produced. That does not mean every + expression is slow enough to matter. The runtime and compiler can make simple cases efficient, and the readability benefit of + or interpolation is often more important than introducing a builder.
Use this mental model:
- Few pieces, known up front: concatenation or interpolation.
- Collection of values:
string.Joinorstring.Concat. - Many incremental appends:
StringBuilder.
A useful rule of thumb from the official guidance is that the best choice depends on whether you are joining a fixed set of values, a collection, or building piece by piece in a loop.
Deep dive
Concatenation with + creates a new string value for the result. If you chain a few operands, the code can still be perfectly reasonable because the whole expression is simple and readable. Interpolation often wins here because it keeps the sentence structure visible and reduces argument-order mistakes.
StringBuilder works differently. It maintains an internal buffer and grows that buffer as you append. This makes it valuable when the text is assembled in many steps, such as a report, log payload, SQL-like text generation, or a loop that appends unknown amounts of content.
The key trade-off is not “allocation versus no allocation.” The real trade-off is:
- concatenation/interpolation: simpler code, fine for short fixed output;
- StringBuilder: more moving parts, better for repeated appends.
This is why interview answers should avoid absolute statements. Saying “StringBuilder is always faster” is too broad. In small cases, the overhead of setting up a builder can erase the benefit. In large loops, repeated + can create unnecessary intermediate strings and pressure the GC.
Failure modes
Common mistakes include:
- using
StringBuilderfor two or three pieces of text where interpolation would be clearer; - repeatedly creating new builders inside a loop instead of reusing one where appropriate;
- choosing
+inside a hot loop that appends many fragments; - forgetting that
string.Joinis often the best answer for arrays or lists; - treating benchmark results from one tiny sample as a universal rule.
Also remember that StringBuilder is not magic. If you already have a stream-oriented workflow, writing directly to the stream may be better than buffering everything into a large string first.
Interview drill
Answer these aloud:
- When would you choose interpolation over
StringBuilder? - Why is
string.Joinoften better than manually concatenating a list? - What makes repeated
+in a loop different from a single concatenation expression? - Why is “
StringBuilderis always faster” a bad interview answer? - What other concern besides speed should drive your choice?
A strong answer mentions readability, the number of fragments, whether the text comes from a collection, and whether the output is built incrementally.
Revision checklist
stringis immutable.+and interpolation are best for small, fixed text assembly.string.Joinis best for delimited collections.StringBuilderis best for many appends or unknown final size.- Reuse or pre-size a builder when you know the workload.
- Prefer clarity first, then optimize the hot path you can measure.
Production code
The example below compares two realistic styles of building the same report. It also uses a deterministic validation check so the output can be verified exactly.
Code walkthrough
The concatenation version is easy to read, but each += produces a new string result. That is acceptable for a small list and makes the intent obvious.
The StringBuilder version expresses the same logic using in-place appends. It is a better fit when the loop is long or the final text is large. If you know the approximate size, you can also pre-size the builder to reduce growth operations.
The important interview takeaway is not to memorize a slogan. Instead, map the API to the workload:
- fixed and small: interpolation or
+ - collection:
string.Join - many appends:
StringBuilder
That choice is usually more valuable than prematurely optimizing one line of code.
Executable code examples
Compare concatenation and StringBuilder for the same output
Program.cs
using System.Text;
var names = new[] { "Ada", "Grace", "Linus" };
string concatenated = BuildWithConcatenation(names);
string built = BuildWithStringBuilder(names);
Console.WriteLine(concatenated == built ? "PASS" : "FAIL");
Console.WriteLine(built);
static string BuildWithConcatenation(string[] names)
{
string result = "Names:";
for (int i = 0; i < names.Length; i++)
{
result += i == 0 ? " " : ", ";
result += names[i];
}
return result;
}
static string BuildWithStringBuilder(string[] names)
{
var sb = new StringBuilder();
sb.Append("Names:");
for (int i = 0; i < names.Length; i++)
{
sb.Append(i == 0 ? " " : ", ");
sb.Append(names[i]);
}
return sb.ToString();
}