今回は、C#のStringBuilderで文字列操作のパフォーマンスを最適化する方法をご紹介します。
StringBuilderとは
StringBuilderは、C#で文字列を効率的に操作するためのクラスです。
通常の文字列連結では、連結のたびに新しい文字列オブジェクトが生成されます。
これに対してStringBuilderは、内部バッファを使って文字列を連続的に扱うため、オブジェクトの再生成を最小限に抑えられます。
大量の連結や挿入・削除を行う場合でも、パフォーマンス面で大きなメリットがあります。
基本的な使い方
ここではStringBuilderの初期容量設定やAppendメソッドなど、よく使われる機能について解説します。
初期容量の設定
初期容量を指定せずにStringBuilderを生成すると、内部で必要に応じてバッファが再確保されます。
連結する文字数が事前にわかっている場合は、StringBuilderのコンストラクタで初期容量を指定するのがおすすめです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; using System.Text; class Program { static void Main() { // 最終的に想定する文字数が分かっている場合は、初期容量を設定する int expectedLength = 1024; StringBuilder sb = new StringBuilder(expectedLength); sb.Append("初期容量を設定しておくと、"); sb.Append("バッファの再確保が減り、パフォーマンスが向上します。"); Console.WriteLine(sb.ToString()); } } |
初期容量を設定しておくと、
バッファの再確保が減り、パフォーマンスが向上します。
AppendやAppendLineの利用
Appendは、文字列を末尾に連結するメソッドです。
改行を挟みたい場合はAppendLineを利用すると便利です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System; using System.Text; class Program { static void Main() { StringBuilder sb = new StringBuilder(); sb.Append("Hello, "); sb.AppendLine("World!"); sb.AppendLine("AppendLineを使うと自動で改行が挿入されます。"); Console.WriteLine(sb.ToString()); } } |
Hello, World!
AppendLineを使うと自動で改行が挿入されます。
AppendFormatと文字列補間
書式付き文字列を扱う場合はAppendFormatが便利です。
ただし、文字列補間や複数回のAppend呼び出しでも同等の処理ができるため、可読性とパフォーマンスを考慮しながら使い分けるとよいでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System; using System.Text; class Program { static void Main() { int number = 123; StringBuilder sb = new StringBuilder(); // AppendFormatによる書式設定 sb.AppendFormat("数値は {0} です。", number); sb.AppendLine(); // 文字列補間 + Append sb.Append("数値は "); sb.Append(number); sb.Append(" です。"); Console.WriteLine(sb.ToString()); } } |
数値は 123 です。
数値は 123 です。
ToString()の呼び出しタイミング
ToString()を呼ぶと、StringBuilder内部のバッファから新たに文字列を生成します。
頻繁に呼び出すと余計なオブジェクト生成が増えるため、必要なタイミングだけ呼ぶことが望ましいです。
実用的な具体例
繰り返し処理の中でStringBuilderを再利用しながら文字列を組み立てると、パフォーマンスが向上します。
以下の例ではループ内でAppendを繰り返した後、次の処理に備えてClearメソッドで中身をクリアしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using System; using System.Text; class Program { static void Main() { StringBuilder sb = new StringBuilder(256); for (int i = 0; i < 5; i++) { sb.Append("現在のループカウント: "); sb.Append(i); sb.AppendLine(" 回目です。"); // 完成した文字列を表示 Console.WriteLine(sb.ToString()); // 次のループで使い回すためにクリア sb.Clear(); } } } |
現在のループカウント: 0 回目です。
現在のループカウント: 1 回目です。
現在のループカウント: 2 回目です。
現在のループカウント: 3 回目です。
現在のループカウント: 4 回目です。
注意点
一度大きなバッファサイズになったStringBuilderを再利用すると、次回以降も大きなメモリ領域が確保されたままです。
この点はメモリの無駄遣いにつながる場合があるため、用途に応じて新規インスタンスの作成も検討してください。
StringBuilderはスレッドセーフではありません。
マルチスレッド環境で共有する場合はロックなどの対策が必要です。
AppendやInsertを多用する箇所でも、性能と可読性のバランスを意識しながら使うと良いでしょう。
まとめ
StringBuilderを活用することで、文字列連結によるパフォーマンス低下を大幅に抑えられます。
連結回数が多いときや、挿入・削除操作が多いケースでとくに有効です。
初期容量や再利用などのポイントを押さえ、効果的に使ってみてください。