Skip to Content
Course content

142: Working with StringBuilder for Performance

Click on the "Edit" button in the top corner of the screen to edit your slide content.

One of the most common performance traps I see developers fall into—even experienced ones—is treating strings like they are mutable. In C#, strings are immutable. Every time you "change" a string, you aren't actually changing it; you're creating a brand new string object in memory and throwing the old one away. When you're doing this three or four times, it doesn't matter. When you're doing it inside a loop with a thousand iterations, you're creating a massive amount of garbage for the GC (Garbage Collector) to clean up, and your app will slow to a crawl.

Let's build a simple System Health Report generator. We have a list of server components, and we want to aggregate their statuses into one final report string.

The trap of the plus-equals operator

I'll start the way a lot of people do. I've got a list of status messages, and I just want to smash them together into one big block of text. Here is my first attempt:


var statuses = new List<string> { "CPU: OK", "RAM: Warning", "Disk: OK", "Network: Critical" };
string report = "System Health Report\n";

foreach (var status in statuses)
{
    // I'm just appending each line to the existing string
    report += status + "\n"; 
}

Console.WriteLine(report);

This looks clean, right? But here is the mistake: that report += status + "\n" line is a performance nightmare. Every single time that loop runs, C# allocates a new string in memory to hold the combined result. If I had 10,000 servers to report on, I'd be allocating 10,000 temporary strings. That's a lot of wasted memory and CPU cycles.

Switching to a mutable buffer

To fix this, we use StringBuilder. Think of it as a dynamic buffer—a piece of memory that can grow as you add to it without needing to recreate the entire object every time. I'll rewrite the report generator to use it.


using System.Text;

var statuses = new List<string> { "CPU: OK", "RAM: Warning", "Disk: OK", "Network: Critical" };

// I initialize the StringBuilder here
StringBuilder reportBuilder = new StringBuilder("System Health Report\n");

foreach (var status in statuses)
{
    // Append adds to the existing buffer instead of creating a new string
    reportBuilder.AppendLine(status);
}

// Only at the very end do I convert the buffer into a final string
string finalReport = reportBuilder.ToString();
Console.WriteLine(finalReport);

Notice I used AppendLine() instead of Append(). It's a handy shortcut that adds the current platform's newline character automatically, so I don't have to manually add \n.

Optimizing the initial capacity

If I really want to squeeze out more performance, there's one more trick. By default, StringBuilder starts with a small internal buffer. As you add more text, it has to "grow" that buffer (which involves allocating a larger array and copying the old data over). If I have a rough idea of how big my report will be, I can set the initial capacity upfront to avoid those resize operations.

I'll modify the initialization to tell the StringBuilder to start with 1024 characters of space:


// Starting with 1024 characters of capacity to prevent internal resizing
StringBuilder reportBuilder = new StringBuilder(1024);
reportBuilder.AppendLine("System Health Report");

It's a small detail, but in high-throughput systems, avoiding those internal re-allocations is what separates "working code" from "production-grade code."




📋 Practical Task

Building a CSV Data Exporter

You need to create a method that takes a list of Product objects and converts them into a single CSV-formatted string. Each product has a Name, a Price, and a Sku.

Requirements:

  • Create a Product class with the properties mentioned.
  • Create a list of at least 5 products.
  • Use a StringBuilder to construct the CSV string.
  • The first line of the CSV must be the header: Name,Price,Sku.
  • Each subsequent line should be the product data, comma-separated.
  • The final result should be printed to the console using ToString().
Rating
0 0

There are no comments for now.

to be the first to leave a comment.