StringBuilder
A receipt cannot be corrected, but a whiteboard can. You add a word to it, rub out a letter, write in a new one, and it is the same board all along. When text has to be built piece by piece for a long time, it is handier to write on a board and print the receipt once, when everything is ready.
Let's see what happens when a string is built in a loop with +=:
string line = "";
for (int i = 1; i <= 5; i++)
{
line += i;
}
Console.WriteLine(line); // 12345The result is right, but let's count the work. A string cannot be changed, so each += creates a new string and copies all the text built so far into it:
- The first pass creates
"1". - The second creates
"12": it copies1and adds2. - The third creates
"123"and copies two characters already. - The fourth creates
"1234"and copies three characters. - The fifth copies four characters for the sake of one new one.
In five passes the program created five strings of 1 to 5 characters and wrote 1 + 2 + 3 + 4 + 5 = 15 characters into them. With 10,000 pieces of one character each, += writes 1 + 2 + … + 10,000, that is, 50,005,000 characters into new strings. The work grows as the square of the number of pieces.
StringBuilder
StringBuilder is that very board: it keeps text that can change in a buffer, a piece of memory you can keep adding to. The Append method adds a piece to the end without creating a new string, and ToString() at the end creates the finished string once:
using System.Text;
var sb = new StringBuilder();
for (int i = 1; i <= 5; i++)
{
sb.Append(i);
}
string line = sb.ToString();
Console.WriteLine(line); // 12345
Console.WriteLine(sb.Length); // 5Let's go through the example line by line:
using System.Text;brings in the namespace whereStringBuilderlives. More on this below.new StringBuilder()creates an empty board.varfits here: the type is visible on the right.sb.Append(i)adds the text of the numberito the end. The old characters stay in place, and they need no copying.sb.ToString()makes an ordinary string"12345"out of the board.sb.Lengthis how many characters are on the board right now.
For 10,000 pieces, StringBuilder writes each character once, and ToString() copies all of them into the string once more. That makes about 20,000 characters written instead of more than 50 million.
Namespaces and the using directive
.NET types are sorted into named groups. Such a group is called a namespace: Console lives in the System namespace, and StringBuilder in System.Text. A .NET 10 program brings in System and several other namespaces by itself, but System.Text is not among them.
The line using System.Text; at the very top of the file is a using directive: it brings the namespace into the file. After it you can write StringBuilder by its short name.
The board can be edited
A board lets you do more than add text. StringBuilder can do four more things:
Insertputs text at a given position, for example at the start;Replacereplaces a piece right on the board, with no new string;sb[4] = 'C'changes one character, which a string does not allow;Clear()rubs out everything, andLengthbecomes0.
using System.Text;
var sb = new StringBuilder("cat");
sb.Append('s');
sb.Insert(0, "two ");
sb[4] = 'C';
Console.WriteLine(sb.ToString()); // two Cats
sb.Replace("two", "three");
Console.WriteLine(sb.ToString()); // three Cats
sb.Clear();
Console.WriteLine(sb.Length); // 0Let's go through it line by line:
new StringBuilder("cat")creates a board withcatalready written on it.Append('s')addss: the board holdscats.Insert(0, "two ")inserts text at index0:two cats.sb[4] = 'C'changes the character at index4, the first letter ofcats:two Cats.Replace("two", "three")changestwotothree:three Cats.Clear()rubs out everything, andLengthbecomes0.
This is where the board and StringBuilder part ways. A board has one size, and when it runs out of room there is nowhere to write. In that case StringBuilder adds another piece of memory by itself, and what is already written stays in place.
When you need StringBuilder
Interviewers often ask this: why do we need StringBuilder if there is +? The answer has two parts:
- a string is immutable, so each
+=in a loop creates a new string and copies all the text built so far into it; StringBuilderadds the pieces to one buffer that can change and creates the string once, inToString().
For two or three pieces you do not need StringBuilder. The compiler turns the expression a + b + c into one call that creates one string, and interpolation reads even better.
Common mistake
The namespace was not brought in:
var sb = new StringBuilder(); // ✗
sb.Append("Hi");
Console.WriteLine(sb.ToString());error CS0246: The type or namespace name 'StringBuilder' could not be found (are you missing a using directive or an assembly reference?)The program does not compile: the compiler looks for StringBuilder in the namespaces brought in and does not find it. The message itself hints at the cause in parentheses: a using directive may be missing. Add using System.Text; as the first line of the file.
Key points
- Each
+=on a string creates a new string and copies all the text, so the work of a+=loop grows as the square of the number of pieces. StringBuilderholds text that can change:Appendadds,Insert,Replaceandsb[i]edit in place, andToString()creates the string.StringBuilderlives in theSystem.Textnamespace, and the file starts withusing System.Text;.- For a few pieces
+or interpolation is enough;StringBuilderis for building in a loop.