Quick Reference
StringBuilder는 루프나 여러 단계에서 텍스트를 반복 누적할 때 씁니다. Append와 AppendLine으로 끝에 붙이고, 최종 문자열이 필요한 시점에 ToString()을 한 번 호출합니다. 짧고 고정된 몇 조각의 문장은 $"..."가 더 간결합니다.
var text = new StringBuilder(capacity: 256);
text.Append("name: ").AppendLine("Mina");
text.Append("scores: ").AppendJoin(", ", [90, 85, 100]);
string result = text.ToString();Length는 현재 문자 수,Capacity는 확보된 문자 저장 공간입니다.- 예상 결과 길이가 크면 생성자
capacity또는EnsureCapacity로 확장 횟수를 줄입니다. - 한 인스턴스를 여러 스레드가 동시에 변경하지 않습니다.
추가와 변경 API
대부분의 변경 메서드는 같은 StringBuilder를 반환하므로 체이닝할 수 있습니다. Append 계열은 뒤에 붙이고, Insert·Remove·Replace는 기존 위치를 바꿉니다.
var builder = new StringBuilder("Mina");
builder.Append(' ')
.AppendFormat("score={0:N0}", 1200)
.AppendLine();
builder.Insert(0, "[player] ");
builder.Replace("Mina", "Jin");
builder.Remove(0, 9);
Console.WriteLine(builder.ToString());AppendFormat은 composite formatting을 사용합니다. 형식화 문화권이 중요하면 AppendFormat(IFormatProvider, ...) 오버로드를 씁니다. 컬렉션에 구분자를 넣는 작업은 반복문에서 마지막 쉼표를 지우기보다 AppendJoin이 의도를 더 정확히 드러냅니다.
builder.Clear();
builder.AppendFormat(CultureInfo.InvariantCulture, "rate={0:F2}", 0.85);
builder.AppendLine();
builder.AppendJoin(" | ", new[] { "build", "test", "deploy" });중간 ToString()은 그 시점의 새 string을 만듭니다. 진행 상황을 정말 기록해야 할 때 외에는 루프 안에서 매번 호출하지 않고, 문자열을 건네야 하는 경계에서만 호출합니다.
용량과 비용
StringBuilder()의 기본 Capacity는 16이며, 필요한 공간이 부족하면 용량을 확장합니다. 이 확장 방식은 구현과 버전에 의존할 수 있으므로 특정 성장 비율을 코드 설계의 전제로 두지 않습니다. 대략적인 최종 길이를 안다면 처음부터 확보하는 편이 큰 텍스트에서 재할당과 복사를 줄일 수 있습니다.
var report = new StringBuilder(capacity: 8_192);
report.EnsureCapacity(16_384);
Console.WriteLine($"{report.Length}/{report.Capacity}");Insert, 중간 Remove, 전체 Replace는 앞뒤 문자를 옮기거나 찾아야 하므로 대용량 텍스트의 반복 편집에는 비용이 큽니다. 순차적으로 생성하는 보고서·CSV·로그 본문에는 잘 맞지만, 임의 위치 편집기를 구현하는 자료구조는 아닙니다. Clear()는 내용을 비워 재사용하게 하지만 메모리를 반드시 반환하는 API로 쓰면 안 됩니다.
string과의 선택
string은 불변이고 StringBuilder는 변경 가능한 문자 버퍼입니다. 반복마다 누적된 전체 텍스트를 새 문자열로 만드는 패턴은 복사량이 커질 수 있습니다. 다만 컴파일러가 알 수 있는 작은 연결이나 한 번의 보간에는 StringBuilder를 억지로 도입할 이유가 없습니다.
string label = $"{name}: {score}"; // 짧은 단일 결과
var csv = new StringBuilder(); // 많은 행을 순차적으로 누적
foreach (var row in rows)
csv.Append(row.Id).Append(',').AppendLine(row.Name);성능 판단은 문자열 수, 예상 길이, 호출 빈도로 합니다. 경계가 애매하면 프로파일링으로 할당량과 실제 병목을 확인합니다. StringBuilder 하나를 static 필드로 공유해 할당을 줄이려 하면 내용이 섞이고 동시성 문제가 생깁니다.
자주 틀리는 부분
ToString()뒤에도 builder는 살아 있으며 이후Append할 수 있지만, 이미 만든 string은 바뀌지 않습니다.Clear()는 문자열 내용을 지울 뿐 용량을 즉시 축소하거나 메모리 반환을 보장하지 않습니다.- 동시
Append는 안전하지 않습니다. 공유가 필요하면 호출자별 builder를 만들거나 동기화 범위를 별도로 설계합니다. - 사용자 입력을 SQL·HTML로 누적한다고 해서 escaping·parameterization 문제가 해결되지는 않습니다.
참고 링크
1 sources