TheDeveloperBlog.com


C# StringBuilder Mistake

StringBuilder mistake. Sometimes StringBuilder code has inefficient string appends in it. StringBuilder is an optimization, except when it is used poorly—then it is a mess. We optimize StringBuilder code that has this mistake.

StringBuilder Append

Example. First I have seen code like I show next in the real-world. Some C# code that I once installed on this web site for an advertising company made this mistake. Let us first look at the mistake.

StringBuilder code with performance problem: C#

static void Test1()
{
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < _iterations; i++)
    {
	string extra = i.ToString();
	string before = "okay" + extra;
	string url = "http://sometest.com/" + extra;
	string text = "Some Test" + extra;
	string after = "That's Good" + extra;

	builder.Append(@"<li style=""float: right; clear: none;
display: block; margin: 0; padding: 0;"">" +
	    before + @" <a href=""" + url + @""">" + text + "</a> " + after + "</li>");
    }
}

We declare a StringBuilder, which is great for this situation. It uses the plus operator. The five string declarations in the inner loop are just there for the benchmark. Please look at the lines with Append.

It is a mess. I apologize for the syntax mess in the last part of the loop above. You doubtless have a lot of code that looks like this or worse. What this code does is build an HTML string of list elements.

Note: It is not optimal—this is the "before" code that has a hidden inefficiency.


Example 2. When you use StringBuilder, don't also use +. The plus operator creates a bunch of temporary strings. We can eliminate these for better performance. We simply pass the strings directly to Append on StringBuilder. It chains Appends.

string.Concat

Tip: This syntax is the same as calling builder.Append() over and over again, just shorter.

Faster StringBuilder implementation: C#

static void Test2()
{
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < _iterations; i++)
    {
	string extra = i.ToString();
	string before = "okay" + extra;
	string url = "http://sometest.com/" + extra;
	string text = "Some Test" + extra;
	string after = "That's Good" + extra;

	builder.Append(@"<li style=""float: right; clear: none;
display: block; margin: 0; padding: 0;"">").Append(
	    before).Append(@" <a href=""").Append(url).Append(@""">").Append(
	    text).Append("</a> ").Append(after).Append("</li>");
    }
}

After benchmarking, the figures shows the time for the method to run 1000 iterations in the inner loop 1000 times. The memory usage isn't big here because the StringBuilder doesn't grow too large in each of the 1000 runs.

Optimization results
    It is faster to avoid concatenating strings inside Append calls.

Before, with concat:     1841 ms
After, separate Appends: 1154 ms [faster]


Summary. We looked at a common mistake found when using StringBuilder in real-world programs. You should avoid using the + concatenation operator in the same statements as StringBuilder. This can improve performance by 40%.

Opinion: I think the best option is to use the syntax in the final example. Placing Append on separate lines is also acceptable.