最初にStringBuilder
クラスを使用することについて少し混乱しています。
string
オブジェクトの連結操作は、常に既存のstring
と新しいデータから新しいオブジェクトを作成します。StringBuilder
オブジェクトは、新しいデータの連結に対応するためのバッファーを維持します。空きがある場合、新しいデータがバッファの最後に追加されます。それ以外の場合は、新しい大きなバッファーが割り当てられ、元のバッファーのデータが新しいバッファーにコピーされてから、新しいデータが新しいバッファーに追加されます。
しかし、StringBuilder
の新しいインスタンスを作成しないようにするために、String
インスタンスを作成するポイントはどこにありますか? 「1対1」で取引されているようです。
static void Main(string[] args)
{
String foo = "123";
using (StringBuilder sb = new StringBuilder(foo)) // also sb isn't disposable, so there will be error
{
sb.Append("456");
foo = sb.ToString();
}
Console.WriteLine(foo);
Console.ReadKey();
}
なぜ使うべきではないのか
+=
Edit:わかりました、StringBuilder
(まだこれはコード標準では正しいです)が、これは1つのstring
だけで使用する価値はありませんか?
変更不変string
sのような構造は、構造をコピーすることで実行する必要があり、それにより、より多くのメモリを消費し、アプリケーションの実行時間(GC
時間なども増加します)。
StringBuilder
は、同じ可変オブジェクトを操作に使用することでこの問題を解決します。
ただし:
コンパイル時にstring
を次のように連結する場合:
string myString = "123";
myString += "234";
myString += "345";
実際にそのようなものにコンパイルされます:
string myString = string.Concat("123", "234", "345");
この関数は、関数に入るStringBuilder
sの数がわかっているため、string
を使用するよりも高速です。
そのため、コンパイル時に既知のstring
連結の場合は、string.Concat()
を優先する必要があります。
次の場合のようなstring
の不明な数に関しては:
string myString = "123";
if (Console.ReadLine() == "a")
{
myString += "234";
}
myString += "345";
現在、コンパイラはstring.Concat()
関数を使用できませんが、StringBuilder
は、6-7以上のstrings
で連結が行われた場合にのみ、時間とメモリ消費がより効率的になるようです。
悪い練習用法:
StringBuilder myString = new StringBuilder("123");
myString.Append("234");
myString.Append("345");
ファインプラクティスの使用法(if
が使用されていることに注意してください):
StringBuilder myString = new StringBuilder("123");
if (Console.ReadLine() == "a")
{
myString.Append("234");
}
myString.Append("345");
ベストプラクティスの使用法(while
ループが使用されていることに注意してください):
StringBuilder myString = new StringBuilder("123");
while (Console.ReadLine() == "a")
{
myString.Append("234"); //Average loop times 4~ or more
}
myString.Append("345");
string
は不変クラスです。変更することはできません。新しいstrings
を作成するだけです。
したがって、result += a;
と記述すると、その時点で3つの個別のstrings
がメモリにあります:a
、result
の古い値、および新しい値。もちろん、限られた数のstrings
のみを連結する場合、これはまったく問題ありません。大規模なコレクションを繰り返し処理するfor
ループでこれを行うと、問題になる可能性があります。
StringBuilder
クラスは、これらの場合にパフォーマンスを改善します。新しいstrings
を作成して連結の結果を保存する代わりに、同じオブジェクトを使用します。したがって、stringBuilder.Append(a);
を使用する場合、「result
の古い値」に相当するものはありません。
このメモリ効率にはもちろん価格が伴います。少数のstrings
a StringBuilder
を連結するだけでは、不変のstring
クラスに比べてオーバーヘッドが大きくなるため、速度に関して効率が低下することがよくあります。
心に留めておくべきことの1つは、.ToString()
を呼び出すとStringBuilder
の新しいコピーが作成されるため、中間文字列が必要なときにstring
の効率が低下する可能性があることです。
その理由は、strings
が不変であるためです。 string
を連結するとき、新しいstring
を作成します。そのため、多くのstrings
を連結する必要がある場合、多くのobjects
を作成します。各string
が1回使用されるため、これはメモリの点ではあまりコストがかかりません。ただし、GC
には追加の作業が必要です。
StringBuilder
ただし、毎回同じobject
を使用しますが、使いやすさが犠牲になります。