Probably what you read was a "good practice" (which I am a critic of). I myself fall into this nonsense when I write because we do not always have time to explain all the details, but if one accepts someone’s statement without a context is just following such "good practices" and may not have the expected result, how that can be the opposite and become a bad practice.
In fact the StringBuilder
is recommended when you have to add several strings in one. But if this operation is the only one and you don’t have to do other actions in the loop then you don’t have to use the StringBuilder
, because I think the Concat()
uses a StringBuilder
internally, so you get a code one Liner.
But let’s be sure and make one benchmark:
using System;
using static System.Console;
using System.Diagnostics;
using System.Text;
public class Program {
const int Limit = 100000;
static int[] dataInt = new int[Limit];
static string[] dataString = new string[Limit];
public static void Main() {
for (int i = 0; i < Limit; i++) {
dataInt[i] = i;
dataString[i] = i.ToString();
}
Time(ConcatenationInt);
Time(JunctionInt);
Time(BuilderInt);
Time(AdditionInt);
Time(ConcatenationString);
Time(JunctionString);
Time(BuilderString);
Time(AdditionString);
}
static void Time(Func<int> action) {
var sw = Stopwatch.StartNew();
int result = action();
sw.Stop();
WriteLine($"{result} - {sw.ElapsedTicks:000,000,000} - {action.Method.Name}");
GC.Collect();
GC.WaitForPendingFinalizers();
}
static int AdditionInt() {
var tmp = "";
for (int i = 0; i < Limit; i++) tmp += dataInt[i];
return tmp.Length;
}
static int AdditionString() {
var tmp = "";
for (int i = 0; i < Limit; i++) tmp += dataString[i];
return tmp.Length;
}
static int ConcatenationInt() => string.Concat(dataInt).Length;
static int ConcatenationString() => string.Concat(dataString).Length;
static int JunctionInt() => string.Join("", dataInt).Length;
static int JunctionString() => string.Join("", dataString).Length;
static int BuilderInt() {
var tmp = new StringBuilder();
for (int i = 0; i < Limit; i++) tmp.Append(dataInt[i]);
return tmp.Length;
}
static int BuilderString() {
var tmp = new StringBuilder();
for (int i = 0; i < Limit; i++) tmp.Append(dataString[i]);
return tmp.Length;
}
}
Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.
The ideal is to test on your machine with nothing affecting the execution. Tests in shared environments like the ones used above are not valid. I tried to minimize the effect of GC, but there’s no way in this restricted memory environment.
The conclusion that can be drawn is that in this case the concatenation is great, the junction also, and the construction of the string is an almost as good option, only the individual addition is that it is tragic.
The code of Concat()
can be seen and he does something even a little bit smarter than the StringBuilder
. No . NET Core.
You saw I used the method group passing in the
Time()
? http://answall.com/q/189905/101. In this case the group has only one method, but is still a group.– Maniero
@Got it. It was pretty clear, thanks!
– nmindz