views:

4084

answers:

11

Suppose I have a stringbuilder in C# that does this:

StringBuilder sb = new StringBuilder();
string cat = "cat";
sb.Append("the ").Append(cat).(" in the hat");
string s = sb.ToString();

would that be as efficient or any more efficient as having:

string cat = "cat";
string s = String.Format("The {0} in the hat", cat);

If so, why?

EDIT

After some interesting answers I realised I probably should have been a little clearer in what I was asking. I wasn't so much asking for which was quicker at concatenating a string, but which is quicker at injecting one string into another.

In both cases above I want to inject one or more strings into the middle of a predefined template string.

Sorry for the confusion

A: 

I would suggest not, since String.Format was not designed for concatenation, it was design for formatting the output of various inputs such as a date.

String s = String.Format("Today is {0:dd-MMM-yyyy}.", DateTime.Today);
GateKiller
A: 

It really depends. For small strings with few concatenations, it's actually faster just to append the strings.

String s = "String A" + "String B";

But for larger string (very very large strings), it's then more efficient to use StringBuilder.

Joseph Daigle
+10  A: 

From the MSDN documentation:

The performance of a concatenation operation for a String or StringBuilder object depends on how often a memory allocation occurs. A String concatenation operation always allocates memory, whereas a StringBuilder concatenation operation only allocates memory if the StringBuilder object buffer is too small to accommodate the new data. Consequently, the String class is preferable for a concatenation operation if a fixed number of String objects are concatenated. In that case, the individual concatenation operations might even be combined into a single operation by the compiler. A StringBuilder object is preferable for a concatenation operation if an arbitrary number of strings are concatenated; for example, if a loop concatenates a random number of strings of user input.

Greg
+1  A: 

I think in most cases like this clarity, and not efficiency, should be your biggest concern. Unless you're crushing together tons of strings, or building something for a lower powered mobile device, this probably won't make much of a dent in your run speed.

I've found that, in cases where I'm building strings in a fairly linear fashion, either doing straight concatenations or using StringBuilder is your best option. I suggest this in cases where the majority of the string that you're building is dynamic. Since very little of the text is static, the most important thing is that it's clear where each piece of dynamic text is being put in case it needs updated in the future.

On the other hand, if you're talking about a big chunk of static text with two or three variables in it, even if it's a little less efficient, I think the clarity you gain from string.Format makes it worth it. I used this earlier this week when having to place one bit of dynamic text in the center of a 4 page document. It'll be easier to update that big chunk of text if its in one piece than having to update three pieces that you concatenate together.

saalon
Yes! Use String.Format when it makes sense to do so, i.e. when you're formatting strings. Use string concatenation or a StringBuilder when you're performing mechanical concatenation. Always strive to pick the method that communicates your intention to the next maintainer.
Rob
+25  A: 

String.Format actually uses a StringBuilder internally:

public static string Format(IFormatProvider provider, string format, params object[] args)
{
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }
    StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
    builder.AppendFormat(provider, format, args);
    return builder.ToString();
}

The above code is a snippet from mscorlib, so the question becomes "is StringBuilder.Append() faster than StringBuilder.AppendFormat". Without benchmarking I'd probably say that the code sample above would run more quickly using .Append. But it's a guess, try benchmarking and/or profiling the two to get a proper comparison.

This chap, Jerry Dixon, did some benchmarking:

http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

At the end of the day it depends whether your string formatting is going to be called repetitively, i.e. you're doing some serious text processing over 100's of megabytes of text, or whether it's being called when a user clicks a button now and again. Unless you're doing some huge batch processing job I'd stick with String.Format, it aids code readability. If you suspect a perf bottleneck then stick a profiler on your code and see where it really is.

HTH

Kev
Good old .Net reflector. :D
Russell
A: 

In both cases above I want to inject one or more strings into the middle of a predefined template string.

In which case, I would suggest String.Format is the quickest because it is design for that exact purpose.

GateKiller
+3  A: 

I would expect String.Format to be slower - it has to parse the string and then concatenate it.

Couple of notes:

  • Format is the way to go for user-visible strings in professional applications; this avoids localization bugs
  • If you know the length of the resultant string beforehand, use the StringBuilder(Int32) constructor to predefine the capacity
McDowell
+6  A: 

I ran some quick performance benchmarks, and for 100,000 operations averaged over 10 runs, the first method (String Builder) takes almost half the time of the second (String Format).

So, if this is infrequent, it doesn't matter. But if it is a common operation, then you may want to use the first method.

Vaibhav
A: 

Oh also, the fastest would be:

string cat = "cat";
string s = "The " + cat + " in the hat";
Vaibhav
no, string concatenation is extremely slow, because .NET creates extra copies of your string variables between the concat operations, in this case: two extra copies plus the final copy for the assignment. Result: extremely poor performance compared to `StringBuilder` which is made to optimize this type of coding in the first place.
Abel
Fastest to type maybe ;)
UpTheCreek
A: 

String.Format uses StringBuilder internally...so logically that leads to the idea that it would be a little less performant due to more overhead. However, a simple string concatenation is the fastest method of injecting one string between two others...by a significant degree. This evidence was demonstrated by Rico Mariani in his very first Performance Quiz, years ago. Simple fact is that concatenations...when the number of string parts is known (without limitation..you could concatenate a thousand parts...as long as you know its always 1000 parts)...are always faster than StringBuilder or String.Format. They can be performed with a single memory allocation an a series of memory copies. Here is the proof:

http://blogs.msdn.com/ricom/archive/2004/03/12/performance-quiz-1-of-a-series.aspx

And here is the actual code for some String.Concat methods, which ultimately call FillStringChecked which uses pointers to copy memory (extracted via Reflector):

public static string Concat(params string[] values)
{
    int totalLength = 0;
    if (values == null)
    {
        throw new ArgumentNullException("values");
    }
    string[] strArray = new string[values.Length];
    for (int i = 0; i < values.Length; i++)
    {
        string str = values[i];
        strArray[i] = (str == null) ? Empty : str;
        totalLength += strArray[i].Length;
        if (totalLength < 0)
        {
            throw new OutOfMemoryException();
        }
    }
    return ConcatArray(strArray, totalLength);
}

public static string Concat(string str0, string str1, string str2, string str3)
{
    if (((str0 == null) && (str1 == null)) && ((str2 == null) && (str3 == null)))
    {
        return Empty;
    }
    if (str0 == null)
    {
        str0 = Empty;
    }
    if (str1 == null)
    {
        str1 = Empty;
    }
    if (str2 == null)
    {
        str2 = Empty;
    }
    if (str3 == null)
    {
        str3 = Empty;
    }
    int length = ((str0.Length + str1.Length) + str2.Length) + str3.Length;
    string dest = FastAllocateString(length);
    FillStringChecked(dest, 0, str0);
    FillStringChecked(dest, str0.Length, str1);
    FillStringChecked(dest, str0.Length + str1.Length, str2);
    FillStringChecked(dest, (str0.Length + str1.Length) + str2.Length, str3);
    return dest;
}

private static string ConcatArray(string[] values, int totalLength)
{
    string dest = FastAllocateString(totalLength);
    int destPos = 0;
    for (int i = 0; i < values.Length; i++)
    {
        FillStringChecked(dest, destPos, values[i]);
        destPos += values[i].Length;
    }
    return dest;
}

private static unsafe void FillStringChecked(string dest, int destPos, string src)
{
    int length = src.Length;
    if (length > (dest.Length - destPos))
    {
        throw new IndexOutOfRangeException();
    }
    fixed (char* chRef = &dest.m_firstChar)
    {
        fixed (char* chRef2 = &src.m_firstChar)
        {
            wstrcpy(chRef + destPos, chRef2, length);
        }
    }
}

So then:

string what = "cat";
string inthehat = "The " + what + " in the hat!";

Enjoy!

jrista
A: 

It really depends on your usage pattern.
A detailed benchmark between string.Join, string,Concat and string.Format can be found here: String.Format Isn't Suitable for Intensive Logging

Liran