Append characters or strings together repeatedly, yielding a longer, single string. Avoid the severe performance problem with strings when modifying them. For example, build up a single string with StringBuilder from 1,000 small strings (numbers, or characters). Measure performance and determine best practices.
To start using StringBuilder, you should include the "using System.Text;" namespace in your file. What follows is an example of using StringBuilder with a string we append. (Note that you will almost always use a StringBuilder in a loop.) Look at how string literals are passed to Append.
class Program
{
static void Main(string[] args)
{
//
// Declare a new StringBuilder with the default constructor.
//
StringBuilder builder = new StringBuilder();
builder.Append("The list starts here:"); // Append some text to it.
builder.AppendLine(); // Terminate the above text with a line break.
builder.Append("1 cat").AppendLine(); // Append a string.
//
// Get ahold of the StringBuilder's buffer content.
//
string innerString = builder.ToString();
//
// Display to the screen with debugging class.
//
Debug.WriteLine(innerString);
}
}
You know that StringBuilder will make your appends go faster usually, but I want to note another benefit about StringBuilder. In .NET, there is a concept of "memory pressure", meaning that the more temporary objects created by your app, the more often garbage collection does its thing and relocates memory. Because it creates fewer temporary objects, StringBuilder will reduce memory pressure (and increase performance).
Use StringBuilder to do this. First we must convert our string to a StringBuilder, and then we can call StringBuilder's methods to do these operations. This is faster because, again, it is using char[] arrays and not unchangeable strings. Here is an example.
StringBuilder builder = new StringBuilder(
"This is an example string that is an example.");
builder.Replace("an", "the"); // Replaces 'an' with 'the'.
Debug.WriteLine(builder.ToString());
//
// "This is the example string that is the example."
//
When your requirements do not involve a loop, generally you should avoid StringBuilder. This is because there is a lot of logic in StringBuilder that will be slow on very small operations. Also, this will make the syntax for your code uglier. Here are a couple gotchas you must consider when you study StringBuilder.
As I have noted, almost always your StringBuilder will be used in a loop. This can be a foreach, for, or while loop. Right here I want to present another example of StringBuilder, but in a foreach loop. After the code, I show the final string built.
string[] items = { "Cat", "Dog", "Celebrity" };
StringBuilder builder2 = new StringBuilder("These items are required:").AppendLine();
foreach (string item in items)
{
builder2.Append(item).AppendLine();
}
Debug.WriteLine(builder2.ToString());
// These items are required:
// Cat
// Dog
// Celebrity
I don't offer benchmarks of StringBuilder vs. string, as that is obvious. However, next in this article I test a way of using StringBuilder more effectively as a parameter. It is an algorithmic optimization, not a "micro-optimization". Additionally, it is good to remember that StringWriter, and the HtmlTextWriter class, will have the same optimizations because they are based on StringBuilder.
Here's a tip: use StringBuilder as a method parameter (part of the function signature). This is a significant optimization because it will avoid converting back and forth to strings. What this next code example shows is how you can use StringBuilder parameters and reuse the same StringBuilder. This example compares thousands of StringBuilders to a single one. (Strings alone would be hugely slower.)
/// <summary>
/// Example program class.
/// </summary>
class Program
{
/// <summary>
/// Example strings.
/// </summary>
static string[] _items = new string[] { "cat", "dog", "emu",
"giraffe", "politician" };
/// <summary>
/// Append to the StringBuilder parameter.
/// </summary>
static void AppendToStringBuilder(StringBuilder builderIn)
{
foreach (string item in _items)
{
builderIn.AppendLine(item); // Append to existing StringBuilder.
}
}
/// <summary>
/// Append to a new StringBuilder and return it as a string.
/// </summary>
static string AppendReturnString()
{
StringBuilder builder = new StringBuilder();
foreach (string item in _items)
{
builder.AppendLine(item);
}
return builder.ToString(); // Return as string.
}
/// <summary>
/// Example Main method.
/// </summary>
static void Main(string[] args)
{
long t1 = Environment.TickCount; // Take time.
for (int i = 0; i < 100000; i++) // 3073 ms.
{
StringBuilder builder = new StringBuilder();
for (int a = 0; a < 100; a++)
{
AppendToStringBuilder(builder); // Use as parameter.
}
}
long t2 = Environment.TickCount;
for (int i = 0; i < 100000; i++) // 5039 ms.
{
StringBuilder builder = new StringBuilder();
for (int a = 0; a < 100; a++)
{
builder.Append(AppendReturnString());
}
}
long t3 = Environment.TickCount;
Console.WriteLine((t3 - t2).ToString() + ", " + (t2 - t1).ToString());
//
// --- Results: ---
// 5039, 3073
}
}
Every site will tell you that 'immutable' means something can't be changed. Try to assign to a character in a string, such as |str[0] = 'a'|. You can't do it, because strings cannot be changed. However, character arrays can be changed. StringBuilder uses "mutable" character arrays for its buffer.
This may be because you are putting too much stuff in your StringBuilder. The maximum number of characters in a StringBuilder (its max capacity) is equal to Int32.MaxValue. If this is happening, check for infinite loops or other really serious problems.
We explored the basics of StringBuilder, and drew in some experience with how and when to use it. Pay heed to the mistake I mention above, and note the special syntax you can use. The best way to use StringBuilder is to simply reuse the same one and call Append repeatedly. Finally, always prefer using StringBuilder as a parameter versus using ToString frequently.