Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

System.String vs System.Text.StringBuilder trong C#: Nên dùng cái nào?

Khác biệt cốt lõi

Đặc điểmStringStringBuilder
Tính chấtImmutable (bất biến)Mutable (có thể thay đổi)
Cơ chếMỗi lần sửa → tạo object mớiSửa tại chỗ trong buffer
Bộ nhớTạo nhiều object rác (GC pressure)Một buffer, mở rộng khi cần
Hiệu năng concatO(n²) cho loopO(n) amortized
Thread-safeCó (immutable)Không

Minh họa sự khác biệt


using System;
using System.Text;

class Demo 
{
    static void Main() 
    {
        // String - Immutable
        string s = "Hello";
        StringConcat(s);
        Console.WriteLine($"String: {s}"); // "Hello" - KHÔNG thay đổi!
        
        // StringBuilder - Mutable
        var sb = new StringBuilder("Hello");
        StringBuilderConcat(sb);
        Console.WriteLine($"StringBuilder: {sb}"); // "Hello World" - THAY ĐỔI!
    }
    
    static void StringConcat(string s) 
    {
        s = string.Concat(s, " World"); // Tạo string MỚI, gán cho local variable s
    }
    
    static void StringBuilderConcat(StringBuilder sb) 
    {
        sb.Append(" World"); // Sửa trực tiếp buffer nội bộ
    }
}

Kết quả

String: Hello
StringBuilder: Hello World

Khi nào dùng String?

  • Chuỗi không thay đổi sau khi tạo.
  • Số lượng concatenation ít (≤ 5-10).
  • Cần thread safety.
  • Key trong Dictionary, switch expression, pattern matching.
  • Interpolation: $"{a} {b}" (compiler tối ưu thành string.Concat hoặc StringBuilder).

Khi nào dùng StringBuilder?

  • Concatenation trong loop hoặc nhiều lần.
  • Xây dựng chuỗi lớn (HTML, JSON, SQL, log).
  • Cần Insert, Remove, Replace thường xuyên.
  • Performance critical path.

Benchmark So sánh


using System.Diagnostics;
using System.Text;

var iterations = 10000;

// String concat in loop - CHẬM
var sw1 = Stopwatch.StartNew();
string s = "";
for (int i = 0; i < iterations; i++) 
{
    s += "x"; // Tạo string mới mỗi lần
}
sw1.Stop();

// StringBuilder - NHANH
var sw2 = Stopwatch.StartNew();
var sb = new StringBuilder();
for (int i = 0; i < iterations; i++) 
{
    sb.Append("x");
}
string result = sb.ToString();
sw2.Stop();

Console.WriteLine($"String += : {sw1.ElapsedMilliseconds} ms");
Console.WriteLine($"StringBuilder: {sw2.ElapsedMilliseconds} ms");
// Kết quả điển hình: String ~2000ms, StringBuilder ~2ms

StringBuilder Best Practices


// 1. Khởi tạo với capacity ước lượng (tránh resize)
var sb = new StringBuilder(estimatedLength * 10); // hoặc 256 default

// 2. Append overloads hiệu quả
sb.Append("text");
sb.AppendLine("line");
sb.AppendFormat("{0:C}", price);
sb.AppendJoin(", ", items); // .NET Core 2.0+

// 3. Clear và reuse (tránh alloc mới)
sb.Clear();
sb.Append("new content");

// 4. ToString() không copy (trừ khi cần modify sau)
string result = sb.ToString(); // O(1) - trả về string từ buffer nội bộ (copy-on-write)

String.Interpolation & Compiler Optimization


// C# 10+: InterpolatedStringHandler - compiler tự tối ưu
public void Log(string message, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] 
    ref System.Runtime.CompilerServices.DefaultInterpolatedStringHandler handler) { }

// Sử dụng bình thường - compiler chọn StringBuilder nếu cần
Log($"User {user.Id} performed {action} at {DateTime.Now}");

// string.Concat vs StringBuilder
// 2-4 args: string.Concat nhanh nhất
// 5+ args hoặc loop: StringBuilder

Span/ArrayPool - Hiệu năng cực đại (.NET Core 2.1+)


using System.Buffers;

public string BuildLargeString(IEnumerable parts) 
{
    // Thuê buffer từ pool
    var buffer = ArrayPool.Shared.Rent(1024);
    try 
    {
        var span = buffer.AsSpan();
        int pos = 0;
        
        foreach (var part in parts) 
        {
            part.CopyTo(span[pos..]);
            pos += part.Length;
        }
        
        return new string(span[..pos]);
    }
    finally 
    {
        ArrayPool.Shared.Return(buffer);
    }
}

Tóm tắt quyết định

Quy tắc: Mặc định dùng string / interpolation. Chỉ dùng StringBuilder khi: (1) Loop concat, (2) Nhiều thao tác sửa đổi, (3) Benchmark chứng minh bottleneck.