【C#】StringBuilder入門:大量の文字列を高速に連結する理由と使い方

目次

+演算子による文字列連結の問題点

C#で文字列を連結する最も簡単な方法は ++= 演算子を使うことです。

string message = "User: ";
message += "Admin"; // "User: Admin"

この方法は、数回の連結であれば全く問題ありません。しかし、forforeachといったループ処理の中で、何百回、何千回と文字列を += で連結し続けると、深刻なパフォーマンス低下を引き起こす可能性があります。


C#のstringは「不変(Immutable)」

パフォーマンスが低下する原因は、C#のstring型が「不変(Immutable)」であるという特性にあります。

string型の変数は、一度作成されると、その中身(メモリ上のデータ)を変更することはできません。message += "Admin"; という操作は、message変数の末尾にデータを追加しているように見えますが、内部的には以下の処理が行われています。

  1. "User: ""Admin" の両方を格納できる、新しいメモリ領域を確保します。
  2. そこに "User: Admin" という新しい文字列を作成します。
  3. message 変数が、この新しい文字列を参照するように切り替えます。
  4. 古い "User: " の文字列は、やがてガベージコレクション(GC)によって破棄されます。

ループ内でこの操作を10,000回繰り返すと、10,000個の不要な中間文字列オブジェクトが生成・破棄されることになり、これがCPUとメモリに大きな負荷を与えます。


StringBuilderによる解決

この問題を解決するために、C#にはSystem.Text名前空間にStringBuilderクラスが用意されています。

StringBuilderは、内部に可変(変更可能)な文字バッファ(編集領域)を持っています。stringとは異なり、StringBuilderに対する文字列の追加(Append)は、既存のバッFAにデータを書き足していくだけで、新しいオブジェクトを(バッファが満杯になるまでは)生成しません。

これにより、ループ内で大量の文字列を連結する場合でも、非常に高速に処理を行うことができます。


StringBuilder の基本的な使い方

StringBuilderを使用するには、まずSystem.Text名前空間をusingし、クラスをインスタンス化します。

主なメソッド:

  • Append(string value): バッファの末尾に文字列を追加します。
  • AppendLine(string value): バッファの末尾に文字列を追加し、さらに改行文字を追加します。
  • ToString(): 最後に、バッファ内に構築されたすべての文字列を、単一のstring型として取り出します。

コード例:foreachループでの使用

List<string>(文字列のリスト)の各要素を、AppendLineを使用して1行ずつ連結し、最終的なレポート文字列を生成する例です。

using System;
using System.Text; // StringBuilder を使用するために必要
using System.Collections.Generic;

public class StringBuilderExample
{
    public static void Main()
    {
        // 処理対象のデータリスト
        var reportLines = new List<string>
        {
            "Line 1: Server OK",
            "Line 2: Database Connected",
            "Line 3: User 'Guest' login",
            "Line 4: Process Complete"
        };

        // 1. StringBuilder のインスタンスを生成
        var logBuilder = new StringBuilder();

        // 2. ループの「外」でインスタンスを生成するのが重要
        
        logBuilder.AppendLine("--- Log Report Start ---");

        // 3. ループ内で Append / AppendLine を呼び出す
        foreach (var line in reportLines)
        {
            // AppendLine は、文字列を追加した後に改行を追加する
            logBuilder.AppendLine(line);
        }

        logBuilder.AppendLine("--- Log Report End ---");

        // 4. 最後に ToString() で結果を一つの string として取り出す
        string finalLog = logBuilder.ToString();

        // 5. 構築された文字列を出力
        Console.WriteLine(finalLog);
    }
}

出力結果:

--- Log Report Start ---
Line 1: Server OK
Line 2: Database Connected
Line 3: User 'Guest' login
Line 4: Process Complete
--- Log Report End ---

まとめ

string++=による連結は、コードがシンプルで読みやすいですが、ループ内で大量に実行するとパフォーマンスが低下します。

  • 少数の連結: string + や文字列補間($)で問題ありません。
  • forforeachループ内の大量の連結: 必ずStringBuilderを使用します

StringBuilderは、不要なオブジェクト生成とガベージコレクションの負荷を劇的に削減し、アプリケーションの応答性を維持するための必須のツールです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次