C# StringBuilder

Array Class Collections File Keyword String .NET ASP.NET Cast Compression Data Delegate Directive Enum Exception If Interface LINQ Loop Method Number Process Property Regex Sort StringBuilder Struct Switch Time Windows WPF

StringBuilder

Once created, a string cannot be changed. A StringBuilder can be changed as many times as needed. It yields big performance improvements.
It eliminates many string copies,
and in certain loops,
is essential.

Example

This program introduces StringBuilder. It shows how StringBuilder is used to build up a large buffer of characters. We call Append on a StringBuilder instance to add more data to it.

C# language

Append:The Append method can be called directly on its own result, in the same statement.

Because:Append(), and other methods like AppendFormat, return the same StringBuilder.

Based on:

.NET 4.5

Program that uses StringBuilder: C#

using System;
using System.Text;

class Program
{
    static void Main()
    {
	StringBuilder builder = new StringBuilder();
	// Append to StringBuilder.
	for (int i = 0; i < 10; i++)
	{
	    builder.Append(i).Append(" ");
	}
	Console.WriteLine(builder);
    }
}

Output

0 1 2 3 4 5 6 7 8 9

Example 2

Note

Next, we look at some of the other essential methods on the StringBuilder type. The methods shown here allow us to use it effectively in many programs. We append strings and lines.

Note:This example shows no loop, and is not ideal as a program. It is for demonstration purposes.

Program 2: C#

using System;
using System.Text;
using System.Diagnostics;

class Program
{
    static void Main()
    {
	// 1.
	// Declare a new StringBuilder.
	StringBuilder builder = new StringBuilder();

	// 2.
	builder.Append("The list starts here:");

	// 3.
	builder.AppendLine();

	// 4.
	builder.Append("1 cat").AppendLine();

	// 5.
	// Get a reference to the StringBuilder's buffer content.
	string innerString = builder.ToString();

	// Display with Debug.
	Debug.WriteLine(innerString);
    }
}

Output

The list starts here:
1 cat
New keyword, constructor invocation

This example program uses the new keyword to create a StringBuilder instance. Next it adds the contents of its arguments to the buffer in the StringBuilder. Every argument will automatically have its ToString method called.

Append

Then:It calls AppendLine, which does the same thing as Append, except with a newline on the end. We use a terse syntax form.

String type

Finally:ToString returns the buffer. You will almost always want ToString—it will return the contents as a string.

AppendLine

Memory

Garbage collection visualization

StringBuilder will make your appends go faster. But it has another benefit. There is a concept of memory pressure, meaning that the more temporary objects created, the more often garbage collection runs.

So:StringBuilder creates fewer temporary objects and adds less memory pressure.

StringBuilder Memory

Replace

Replace

We next use StringBuilder to replace characters in loops. First we convert the string to a StringBuilder. We then call StringBuilder's methods. This is faster. The StringBuilder type internally uses character arrays.

Caution:The Replace method will replace all instances of the specified value. To replace one instance, you will need a custom method.

Program that uses Replace: C#

using System;
using System.Text;

class Program
{
    static void Main()
    {
	StringBuilder builder = new StringBuilder(
	    "This is an example string that is an example.");
	builder.Replace("an", "the"); // Replaces 'an' with 'the'.
	Console.WriteLine(builder.ToString());
	Console.ReadLine();
    }
}

Output

This is the example string that is the example.

Immutable

Concept: a discussion topic

Immutable indicates that the data being pointed at is not changeable. To see an example of an immutable object, try to assign to a character in a string. This causes a compile-time error.

Compile-Time Error

And:This happens because the string type does not define a set accessor. It cannot be modified once changed.

But:Character arrays can be changed. Internally StringBuilder uses mutable char arrays for its buffer.

AppendFormat

Format

Few things in life are as much fun as formatting strings. With AppendFormat, we add text to a StringBuilder based on a pattern. You can use substitution markers to fill fields in this pattern.

Tip:Many versions of AppendFormat in the .NET Framework (such as Console.WriteLine) are implemented with StringBuilder.

Console.WriteLine

However:It is usually faster to call Append repeatedly with all the required parts. But the syntax of AppendFormat may be clearer.

AppendFormat

Loops

Loop

Usually your StringBuilder will be used in a loop. If many appends are needed, sometimes StringBuilder is helpful in other contexts. This can be any looping construct. Here is an example of StringBuilder in a foreach-loop.

Foreach

Note:Many looping constructs, including for, while and foreach, are effective when used with StringBuilder.

Loops
Program that uses foreach: C#

using System;
using System.Text;

class Program
{
    static void Main()
    {
	string[] items = { "Cat", "Dog", "Celebrity" };

	StringBuilder builder2 = new StringBuilder(
	    "These items are required:").AppendLine();

	foreach (string item in items)
	{
	    builder2.Append(item).AppendLine();
	}
	Console.WriteLine(builder2.ToString());
	Console.ReadLine();
    }
}

Output

These items are required:
Cat
Dog
Celebrity

Equals

Not equal

You will find that StringBuilder defines an instance method Equals that can be used to compare the capacities and contents of two StringBuilders. This method avoids lots of error-prone code that you write yourself.

Equals

Caution:The Equals method will return false if the capacities of the objects are different, even if their data is identical.

Clear

Question and answer

How can you clear the data inside your StringBuilder that you have already appended? Sometimes it is best to allocate a new instance. Other times, you can assign the Length property to zero or use the Clear method.

Clear

Further:Please see the performance section and the "Cache objects" optimization tip for ways to use Clear to avoid allocations.

Argument

Method

We explore how to use the StringBuilder type as an argument. This is a nice optimization. It will avoid converting back and forth to strings. This example shows StringBuilder arguments.

Tip:Eliminating allocations of strings (and StringBuilders) is a highly effective way to improve program performance.

Caution:Usually it is best to use descriptive names, not "A1" or "b". But this website follows its own rules.

Program that creates many StringBuilders: C#

using System;
using System.Text;

class Program
{
    static string[] _items = new string[]
    {
	"cat",
	"dog",
	"giraffe"
    };

    /// <summary>
    /// Append to a new StringBuilder and return it as a string.
    /// </summary>
    static string A1()
    {
	StringBuilder b = new StringBuilder();
	foreach (string item in _items)
	{
	    b.AppendLine(item);
	}
	return b.ToString();
    }

    static void Main()
    {
	// Called in loop.
	A1();
    }
}

Program that uses StringBuilder argument: C#

using System;
using System.Text;

class Program
{
    static string[] _items = new string[]
    {
	"cat",
	"dog",
	"giraffe"
    };

    /// <summary>
    /// Append to the StringBuilder param, void method.
    /// </summary>
    static void A2(StringBuilder b)
    {
	foreach (string item in _items)
	{
	    b.AppendLine(item);
	}
    }

    static void Main()
    {
	// Called in loop.
	StringBuilder b = new StringBuilder();
	A2(b);
    }
}

Results

Version 1: 5039 ms
Version 2: 3073 ms

Indexer

Dots: colored circles

It is possible to use the indexer on your StringBuilder instance to access or change certain characters. This syntax is the same as the syntax for accessing characters in a string instance.

Next:The example tests and changes characters in a StringBuilder. It uses the indexer.

Program that uses indexer: C#

using System;
using System.Text;

class Program
{
    static void Main()
    {
	StringBuilder builder = new StringBuilder();
	builder.Append("cat");

	// Write second letter.
	Console.WriteLine(builder[1]);

	// Change first letter.
	builder[0] = 'r';
	Console.WriteLine(builder.ToString());
    }
}

Output

a
rat

Remove

Remove

You can use the Remove method on the StringBuilder type remove a range of characters by index from the internal StringBuilder buffer. As with other StringBuilder methods, this just rearranges the internal buffer.

Here:We remove characters starting at index 4.
We remove three characters past that index.

Program that uses Remove on StringBuilder: C#

using System;
using System.Text;

class Program
{
    static void Main()
    {
	StringBuilder builder = new StringBuilder("Dot Net Perls");
	builder.Remove(4, 3);
	Console.WriteLine(builder);
    }
}

Output

Dot  Perls

Substring

Substring method example

This is a neat trick with the Append method. You can append a substring directly from another string. You do not need to call Substring before calling Append. This improves performance in some situations.

Append Substring

ToString

The ToString method implementation for the StringBuilder type has optimizations. It will not actually copy the data in certain situations. This type has many optimizations that would be hard to duplicate.

ToString

Exception

Error

This type can cause exceptions. You may be get an ArgumentOutOfRangeException if you put too much data in it. The maximum number of characters in a StringBuilder is equal to Int32.MaxValue.

ArgumentOutOfRange Exception

Note:The Int32.MaxValue constant is equal to 2,147,483,647. This is the max length of a StringBuilder.

int.MaxValue

Constructor

Often, you need to Append a string to your StringBuilder directly after allocating it. I found that when you specify that string in the constructor, the overall performance is somewhat improved.

Tip:This optimization can be used with a capacity. Specify the initial string value along with the capacity.

Version 1: C#

var builder = new StringBuilder(10);
builder.Append("Cat");

Version 2: C#

var builder = new StringBuilder("Cat", 10);

Times

38.80 ns
32.47 ns

Discussion

Array type

Character arrays,
specified as char[],
are simpler,
but your code must be more precise. If you know a maximum or absolute size of your output string, and your requirements are simple, use char arrays.

So:The StringBuilder is an optimization for building up strings. A char array is an alternative, and sometimes superior, optimization.

Char ArrayPlus

Sometimes, we make a StringBuilder mistake that reduces speed by about 40%. We use the plus operator on strings within a StringBuilder. This is bad. It results in many temporary assignments and copies in the managed heap.

StringBuilder Mistake

Tip:Please see more possible optimizations of StringBuilder usage in the performance section.

Performance

Performance optimization

StringBuilder is mainly a performance optimization for the string type in certain cases. We test the performance and memory usage of it. We learn when this type is superior to strings.

1. Avoid short appends.A program that appends many strings length of lengths less than 20 characters can be optimized.

Append Performance

2. Cache objects.The StringBuilder instance itself can be cached as a field. This avoids a separate allocation each time it is used.

Cache

3. Avoid some data types.Certain data types, such as ints and bools are slower to append. You can use logic to append a char instead.

Data Types

4. Prefer chars.On some systems appending two chars, one after another, is faster than appending a two-character string literal.

Append Chars

5. Know when to prefer strings.Appending two or three strings together is more efficient than using StringBuilder.

StringBuilder Comparison

6. Append digits.We access each digit using logic, and then append that digit as a char.

Append Integers

7. Set capacity.Internally, the StringBuilder manages a capacity buffer where the data is stored.

Capacity

StringReader

Letters of the alphabet: ABC

We read and write string data with the StringReader and StringWriter types. StringReader loops over and reads lines (or blocks) from a source string. StringWriter is used as a backing store for the HtmlTextWriter.

StringReaderStringWriter

Summary

These secrets are widely known. But this makes them no less effective. StringBuilder can improve the performance of your program—even if you misuse it. By using it in a more optimal way, though, results are better.

C#