When to use String and Stringbuilder

Asked

Viewed 1,398 times

4

There is another question about What is the most appropriate way to concatenate strings?. It explains the possible types of concatenations in C#.

But when should we use System.String and when we should use System.Text.StringBuilder? What is the difference between the two? And, best, when nay utilise?

  • I don’t understand that it’s the same question. In referenced, one asks the types of concreteness, here I ask when to use concatenation and when to use Stringbuilder.

1 answer

7


First let’s meet the two guys.

System.String

The guy string is a reference type within the . NET Framework. Therefore it "lives" only in memory heap, a simple and quick-access object storage memory.

But its main feature is the type string is a immutable object, that is, when we define a new value to a type string, what happens is that the old value is completely destroyed, and in a new memory position is stored the new value, then the object string now refers to that new position in the memory.

See in the image below what is this behavior.

Fonte: PASIONATE TALKS Source: https://passionatetalks.wordpress.com/2014/07/20/why-strings-are-immutable-in-dot-net/

This "recreation" of string every concatenation is, in a way, costly

System.Text.Stringbuilder

The guy StringBuilder, is already a complex type, represents a mutable type of string, ie a mutable type of string.

It works like this: Every time a new string is added, it breaks this string in chars and stores one by one on one char[] intern. See your source code here.

The advantage said is that it ensures that a value will never be "recreated", as with the type string. Each time a new value is add, it just inserted into your stack.

This, of course, comes with other advantages. With StringBuilder it is possible to remove a single char of the middle of the chain, as well as it is possible to insert a char in the middle of the string. Both only specifying the position per index.

When to use each?

If Stringbuilder is more performative than string, then I must always wear StringBuilder for concatenation?

Of course not. It should be used when really worth it. Important not to forget that the StringBuilder is a complex type, must be instantiated. Poranto is more expensive to be initialized.

In the case of a simple concatenation as the example below, it would not be worth using StringBuilder:

var nome = "Thiago";
var sobrenome "Lunardi";
var nomeCompleto = nome +" "+ sobrenome;
nomeCompleto;
> "Thiago Lunardi"

For it is a short execution - only a concatenation - making, in this case, only the use of the type string more efficient.

But, already in the case below, it would be worth a refactoring:

var nomesDosAlunos = string.Empty;
foreach(var aluno in salaDeAula.Alunos)
    nomesDosAlunos += aluno.Nome + ',';

After all, in this case, every loop, a new string is rebuilt. This would be a good opportunity to gain performance with StringBuilder.

var nomesDosAlunos = new StringBuilder();
foreach(var aluno in salaDeAula.Alunos)
    nomesDosAlunos.Append(aluno.Nome).Append(',');

There’s room for improvement?

Yes, there is, not much else, but depending on the scenario, the improvement is significant.

In the StringBuilder, each time a new value is added, it needs expand your storage capacity. This requires, even if minimal, a processing time for allocation of the new block.

To speed up, you can initialize the StringBuilder already with the expected size, thus, when adding new values, it will not consume time expanding its blocks.

var nomesDosAlunos = new StringBuilder(salaDeAula.Alunos.Count);
foreach(var aluno in salaDeAula.Alunos)
    nomesDosAlunos.Append(aluno.Nome).Append(',');

Performance test

I wrote a script on . NET Fiddle to make a String vs Stringbuilder performance test.

public class Program
{
    private static Stopwatch _watch = new Stopwatch();
    public static void Main()
    {
        for(var times = 1; times <= 1000; times *= 10)
        {
            var stringTestResult = Test(() => StringTest(times));
            var stringBuilderTestResult = Test(() => StringBuilderTest(times));
            var stringBuilderPresetTestResult = Test(() => StringBuilderPresetTest(times));

            if(times < 1) {times=1;continue;} // first time is warming up, doesn't count
            Console.WriteLine($"Testing against {times} times concatenation.");
            Console.WriteLine($"String: {stringTestResult}");
            Console.WriteLine($"StringBuilder: {stringBuilderTestResult}");
            Console.WriteLine($"StringBuilderPreset: {stringBuilderPresetTestResult}");
            Console.WriteLine();
        }
    }

    public static long Test(Action test)
    {
        _watch.Restart();
        for(var x =0; x<=100; x++) test();
        _watch.Stop();
        var ticks = _watch.ElapsedTicks;        
        return ticks;
    }

    public static void StringTest(int times)
    {
        var s = string.Empty;           
        for(var x = 0; x < times; x++)
            s += ' ';
    }

    public static void StringBuilderTest(int times)
    {
        var s = new StringBuilder();
        for(var x = 0; x < times; x++)
            s.Append(' ');
    }

    public static void StringBuilderPresetTest(int times)
    {
        var s = new StringBuilder(times);
        for(var x = 0; x < times; x++)
            s.Append(' ');
    }
}

The idea is, for guys string and StringBuilder, concatenate several times a char and measure how many ticks were necessary for each operation.

One of the results was the following:

Testing against 1 times concatenation.
String: 17
StringBuilder: 33
StringBuilderPreset: 11

Testing against 10 times concatenation.
String: 37
StringBuilder: 29
StringBuilderPreset: 15

Testing against 100 times concatenation.
String: 584
StringBuilder: 80
StringBuilderPreset: 56

Testing against 1000 times concatenation.
String: 89935
StringBuilder: 658
StringBuilderPreset: 425

Notice that, concatenating a few times, the string is faster than the StringBuilder, however, as the number of concatenations increases, StringBuilder becomes much more performatic.

  • You said string is a primitive type, but if I use code: typeof(string).IsPrimitive he returns me a false, know explain the reason?

  • 1

    @Gabrielcoletta wasn’t the one who said it, so I put the link to list of primitive types to quote the source. I was really curious. I will search and add here what I find.

  • 1

    @Gabrielcoletta really has a nice discussion about it. In the end, I found something more within the context. For . NET, string is a Value Type, not a Reference Type. And this distinction satisfies the content context. I even updated the links. Thanks for the note.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.