In this post, I will show how you can optimize your string operations by using the StingBuilder class and the static class String.
I’ve done it tons of times: Concating string the wrong way. Concatenation is the process of joining strings. And if I have a string s1 = "Hello"
, and I want to append the string " world"
to the string, so i’ll use the + operator overridden from System.Object
.
string s1 = "Hello";
s1 = s1 + " world";
or equivalent:
string s1 = "Hello";
s1 = s1 + " world";
So whats wrong with that. The problem is that a string is immutable: A string cannot change – it’s read-only. So the +
operation does not change s1
, but creates a new concated string, and then points s1
to the new strings location i memory. But the old string still lingers somewhere in the memory. And you string may be long, and you may append to it many times.
But how do we change a string, if a string is immutable. We don’t. We avoid creating the string until its completed, by keeping the “to-be” string in a StringBuilder
until we are ready to copy the result to a real string. The StringBuilder
is a mutable dynamic “string”. As a default, the builder holds 16 bytes of string data, but you can specify another length in the constructor – which you may want to do is you have an idea of how long the final string will be.
How many bytes you’ll need per characters depends on the kind of character. The UTF-8 uses 1-6 bytes per characters – the 127 ASCII characters only uses 1 byte per character. But most importantly: If your StringBuilder
grows larger, it’ll simply expand as needed.
Actually, this is a pretty simple approach, not radical different that working with real strings:
using System.Text;
StringBuilder s1 = new StringBuilder();
s1.Append("Hello");
s1.Append(" world");
Console.Write(s1.ToString());
A different, and less flexible approach is to use the static String.Concat
method:
string s1 = String.Concat("Hello", " world");
This approach is useful when combining different parts of data, e.g. user input, but unlike the StringBuilder
, you will need to know all the parts of the string when it is declared.
3 responses to “Strings the right way”
A third way could be by using
String.format
, likestring s1 = String.format("{0} {1}",
"hello",
"world");
You are forgetting about compiler optimizations.
When the strings are constants it’s ok to use + operator. The compiler is smart enough to translate this to a single string: “Hello world”, which is prefered to a call to
String.Concat
.When not all strings are constants it’s still ok to use + because the whole sequence will be translated to a
string.Concat:
becomes"Hello" + " world " + ", says " + user.Name
String.Concat("Hello world, says ", user.Name)
. I find it more elegant though to writeString.Format("Hello world, says {0}", user.Name)
; this is a little slower thanstring.Concat
, which is the fastest way of concatenating strings. Not inside loops, though :)When strings need to be concatenated using data available in loops, the winner is
StringBuilder
.var builder = new StringBuilder();
foreach (var digit in Enumerable.Range(0, 10))
{
builder.Append(digit + " ");
}
Note: compiler optimizations occur only when the code is optimized, usually in Release builds.
Hi Suiden
Thanks for your comments. You right a long way here, but in my exact example:
string s1 = “Hello”;
s1 = s1 + ” world”;
Even an optimized compilation produces the following MSIL:
.locals init ([0] string s1)
ldstr “Hello”
stloc.0
ldloc.0
ldstr ” world”
call string [mscorlib]System.String::Concat(string, string)
stloc.0
Now, I am not even close to being a IL expert – but this MSIL code is not optimized in the way you describe.
The string “Hello” is pushed onto the stack, and is location stored in the local variable 0 (s1) – then after the concat have been performed (and the result stored on the stack), variable 0 is redirected to the new location.
The pivotal point is, that I create s1 as a named variable first. If i instead write:
s1 = ” Hello” + ” world”;
or
s1 = String.Concat(“Hello”, ” world”);
Only one string is created. So you are right concerning my last example with Concat.