string s = "Hello";
s += " World"; // 實際發生:
// 1. 配置新字串 (11 chars)
// 2. 複製 "Hello"
// 3. 複製 " World"
// 4. s 指向新字串,舊字串等待 GC
每次修改都**配置新記憶體、複製內容**,大量串接會產生大量暫時物件,觸發 Gen 0/1 GC,嚴重影響效能。
var sb = new StringBuilder("Hello", 100); // 初始容量 100
sb.Append(" World"); // 在緩衝區尾端寫入,不配置新物件
sb.AppendLine("!");
sb.Replace("World", "C#"); // 原地取代
string result = sb.ToString(); // 最後一次性轉為 String
| 操作 | String | StringBuilder |
|---|---|---|
| 連接 | + / Concat / Join | Append / AppendLine / AppendFormat |
| 插入 | Insert (回傳新字串) | Insert(index, value) (原地) |
| 移除 | Remove / Substring | Remove(start, length) |
| 取代 | Replace(old, new) | Replace(old, new) |
| 查詢 | IndexOf, Contains, StartsWith | ToString().IndexOf... (需轉字串) |
| 大小寫 | ToUpper/ToLower | 無 (需轉字串處理) |
| 格式化 | string.Format / $"" | AppendFormat |
// String: ~1200 ms, Gen0 GC 200+ 次
string s = "";
for (int i = 0; i < 100000; i++) s += "x";
// StringBuilder: ~5 ms, Gen0 GC 0 次
var sb = new StringBuilder(100000);
for (int i = 0; i < 100000; i++) sb.Append('x');
差距 > 200 倍,GC 壓力歸零。
string.Concat / $"" / string.Join (編譯器優化單次配置)。StringBuilder (指定預估容量避免擴容)。String (API 豐富、不可變安全)。Span + StringBuilder / String.Create (進階)。Capacity:目前緩衝區大小 (可手動設定,擴容通常雙倍)。Length:實際字元數。MaxCapacity:上限 (預設 int.MaxValue),可限制防止惡意/錯誤耗盡記憶體。new StringBuilder(initCapacity) 避免多次擴容複製。
// 零配置格式化範例:產生 "Item_0001" ~ "Item_9999"
string[] items = new string[10000];
for (int i = 0; i < 10000; i++)
{
items[i] = string.Create(10, i, (span, value) =>
{
"Item_".AsSpan().CopyTo(span);
// 手寫 4 位數字格式化
int v = value;
span[9] = (char)('0' + v % 10); v /= 10;
span[8] = (char)('0' + v % 10); v /= 10;
span[7] = (char)('0' + v % 10); v /= 10;
span[6] = (char)('0' + v % 10);
});
}
極致效能場景 (高頻日誌、序列化) 可考慮。
String = 不可變、語意安全、API 豐富,適合大多數業務邏輯。
StringBuilder = 可變緩衝區、批次修改零配置,專為**大量串接/修改**設計。
掌握兩者邊界,善用 `string.Join`、`String.Create` 等現代 API,即可寫出兼具可讀性與高效能的字串處理程式碼。