The answer is that it depends upon how you concatenate. If you use the + operator with static strings, then your friends are correct -- there is no need for a string builder. However, if you use string variables or the += operator, then you are reallocating strings.
The way to really find out what's going on here is to write some code and then decompile it.
Let's build some test code and look at it in Reflector, using the IL view (or you can use ILDASM, whichever you prefer
So first, a baseline -- this method does not concatenate at all:
static void NoConcat()
{
string test = "Hello World";
}
Now here is the IL:
.method private hidebysig static void NoConcat() cil managed
{
.maxstack 1
.locals init (
[0] string test)
L_0000: nop
L_0001: ldstr "Hello World" <----------NO reallocation!
L_0006: stloc.0
L_0007: ret
}
Ok, no surprises, right?
Now lets look at some code that definitely reallocates the string, so we know what that looks like:
static void Concat2()
{
string test = "Hello";
test += " ";
test += "World";
}
Here's the IL, note the reallocations (it calls string.Concat, which causes a new string to be allocated):
.method private hidebysig static void Concat2() cil managed
{
.maxstack 2
.locals init (
[0] string test)
L_0000: nop
L_0001: ldstr "Hello"
L_0006: stloc.0
L_0007: ldloc.0
L_0008: ldstr " "
L_000d: call string [mscorlib]System.String::Concat(string, string)
L_0012: stloc.0
L_0013: ldloc.0
L_0014: ldstr "World"
L_0019: call string [mscorlib]System.String::Concat(string, string)
L_001e: stloc.0
L_001f: ret
}
Ok, now how about a concatenation that doesn't cause a reallocation -- we are going to concatenate static strings with teh "+" operator:
static void Concat1()
{
string test = "Hello" + " " + "World";
}
Here's the IL -- look how smart the compiler is! It does NOT use concat -- it's identical to the first example:
.method private hidebysig static void Concat1() cil managed
{
.maxstack 1
.locals init (
[0] string test)
L_0000: nop
L_0001: ldstr "Hello World"
L_0006: stloc.0
L_0007: ret
}
Now lets have a little fun. What if we mix static strings and variables? (this is where you may still be better off using a stringbuilder)
static void Concat3(string text)
{
string test = "Hello" + " " + text + " World";
}
And the IL. Note that it was smart enough to combine the "Hello" and the " " as a constant, but it still has to do a concat for the text variable:
.method private hidebysig static void Concat3(string text) cil managed
{
.maxstack 3
.locals init (
[0] string test)
L_0000: nop
L_0001: ldstr "Hello "
L_0006: ldarg.0
L_0007: ldstr " World"
L_000c: call string [mscorlib]System.String::Concat(string, string, string)
L_0011: stloc.0
L_0012: ret
}