StringBuilder w C# — kiedy używać i jak działa

Łańcuch string jest niezmienny — każda metoda klasy System.String tworzy nowy obiekt w pamięci (pełne omówienie w artykule Łańcuchy string w C#). Gdy modyfikujesz tekst wielokrotnie, np. w pętli, prowadzi to do tworzenia wielu zbędnych obiektów — dlaczego to realny problem wydajnościowy, tłumaczy osobny artykuł efektywne manipulowanie stringiem. Tutaj skupiamy się na samej klasie StringBuilder — rozwiązaniu tego problemu — i jej pełnym API.
Czym jest StringBuilder?
StringBuilder (z przestrzeni System.Text) to zmienny bufor znaków. Zamiast tworzyć nowy obiekt przy każdej zmianie, modyfikuje zawartość w miejscu i dynamicznie rozszerza pamięć w razie potrzeby. Gotowy tekst pobierasz metodą ToString().
Deklaracja i inicjalizacja
using System.Text;
StringBuilder sb1 = new StringBuilder(); // pusty
StringBuilder sb2 = new StringBuilder("Witaj świecie"); // z zawartością początkowąPojemność początkowa (nie „maksymalna”)
Liczbę całkowitą w konstruktorze często myli się z limitem. To pojemność początkowa bufora — ile znaków pomieści, zanim będzie musiał się rozszerzyć. StringBuilder rośnie automatycznie ponad tę wartość, więc nie jest to twardy limit.
StringBuilder sb = new StringBuilder(40); // pojemność początkowa 40
StringBuilder sb2 = new StringBuilder("Witaj świecie", 40); // zawartość + pojemność początkowaTwardy limit można ustawić osobno — to właściwość MaxCapacity, podawana w konstruktorze new StringBuilder(capacity, maxCapacity). Ustawianie pojemności początkowej to drobna optymalizacja: gdy z góry znasz przybliżony rozmiar, ograniczasz liczbę realokacji bufora. Jeśli dowiesz się o potrzebnym rozmiarze dopiero w trakcie budowania tekstu, możesz dociągnąć pojemność później metodą EnsureCapacity(min) — gwarantuje ona, że bufor pomieści co najmniej min znaków, bez wielokrotnych, mniejszych realokacji po drodze.
Najważniejsze metody
Append(value)— dopisuje tekst na końcu.AppendLine(value)— dopisuje tekst i znak nowej linii.AppendFormat(format, args)— dopisuje sformatowany tekst.Insert(index, value)— wstawia tekst na pozycji.Remove(start, length)— usuwalengthznaków od pozycjistart.Replace(oldValue, newValue)— zamienia wszystkie wystąpienia (działa na znakach i całych łańcuchach).Clear()— czyści bufor.ToString()— zwraca zbudowany łańcuch.
Dostęp do pojedynczego znaku — indekser
W przeciwieństwie do string, gdzie znak pod indeksem jest tylko do odczytu, indekser StringBuilder pozwala też zapisywać pojedynczy znak bez przebudowy całego bufora:
var sb = new StringBuilder("Witaj świecie");
char pierwszy = sb[0]; // 'W'
sb[0] = 'w'; // podmiana jednego znaku — O(1), bez alokacji nowego stringa
Console.WriteLine(sb); // witaj świeciePrzykłady z wynikami
Append i AppendLine
using System;
using System.Text;
var sb = new StringBuilder("Witaj ");
sb.Append("świecie");
sb.AppendLine(" Test"); // dopisuje " Test" + nową linię
sb.Append("kolejny tekst");
Console.WriteLine(sb.ToString());
// Witaj świecie Test
// kolejny tekstAppendFormat
var sb = new StringBuilder("Sumowana kwota to: ");
sb.AppendFormat("{0:C}", 1000);
Console.WriteLine(sb.ToString());
// Sumowana kwota to: 1 000,00 zł (format waluty zależy od kultury)Insert i Remove
var sb = new StringBuilder("Witaj ");
sb.Insert(6, "świecie");
Console.WriteLine(sb); // Witaj świecie
var sb2 = new StringBuilder("Witaj świecie");
sb2.Remove(5, 8); // usuwa " świecie" (8 znaków od indeksu 5)
Console.WriteLine(sb2); // WitajReplace
var sb = new StringBuilder("Witaj świecie");
sb.Replace("świecie", "Marcin");
Console.WriteLine(sb); // Witaj MarcinMethod chaining
Większość metod zwraca ten sam obiekt StringBuilder, więc wywołania można łączyć:
string raport = new StringBuilder()
.AppendLine("=== Raport ===")
.Append("Pozycji: ").Append(42).AppendLine()
.Append("Status: OK")
.ToString();Pułapka: Equals() porównuje bufor, nie treść jak string
Łatwo założyć, że skoro dwa obiekty StringBuilder mają identyczną zawartość tekstową, są sobie “równe” — tak jak dwa identyczne string. To nieprawda dla domyślnego porównania referencyjnego:
var a = new StringBuilder("test");
var b = new StringBuilder("test");
Console.WriteLine(a.Equals(b)); // false — to różne obiekty (Equals sprawdza referencję i pojemność)
Console.WriteLine(a.ToString() == b.ToString()); // true — porównanie zbudowanych stringówJeśli chcesz porównać zawartość dwóch buforów, porównuj wyniki ToString(), a nie same obiekty StringBuilder.
Kiedy używać StringBuilder?
- Tak: budowanie tekstu w pętli, wiele kolejnych modyfikacji, generowanie dużych ciągów (raporty, logi, eksporty — zobacz praktyczny przykład fakturowania w artykule Generowanie dokumentów i raportów).
- Niekoniecznie: przy kilku sklejeniach czytelniejsza jest interpolacja
$"..."—StringBuilderma drobny narzut na utworzenie obiektu.
🚀 Co dalej?
Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →