質問
私がテストするためのテストアプリケーションを作成して、StringBuilderをされている別のインスタンスにデータをコピーし、その長さが現在の容量よりも多くし、Ildasm.exeをして確認しているが、それは同じように見えるとき、それはバッファ育つます。
どのようにStringBuilderを確認するために、新しいインスタンスにそのデータをコピーして、指定の制限により、バッファを成長する?
解決
あなたは、StringBuilderのが実装されているか調べるだけでリフレクターを起動し、それを見てみたい場合。次のようにStringBuilder.Append(string)
のための実装です。
public StringBuilder Append(string value)
{
if (value != null)
{
string stringValue = this.m_StringValue;
IntPtr currentThread = Thread.InternalGetCurrentThread();
if (this.m_currentThread != currentThread)
{
stringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
}
int length = stringValue.Length;
int requiredLength = length + value.Length;
if (this.NeedsAllocation(stringValue, requiredLength))
{
string newString = this.GetNewString(stringValue, requiredLength);
newString.AppendInPlace(value, length);
this.ReplaceString(currentThread, newString);
}
else
{
stringValue.AppendInPlace(value, length);
this.ReplaceString(currentThread, stringValue);
}
}
return this;
}
あなたが探しているものを見つけることなどNeedsAllocation
、GetNewString
とのセクションを見ます。
他のヒント
キャパシティのStringBuilderに割り当てられた連続したメモリを表します。容量は、文字列の> =の長さとすることができます。より多くのデータが容量よりのStringBuilderに追加されたときに、StringBuilderのは自動的に容量を増加させます。容量(すなわち、連続したメモリで埋め、それ以上のバッファ室が利用できない場合)を超えているので、より大きなバッファ領域が割り当てられ、データは、この新しい領域に元のメモリからコピーされます。
これは、新しい「インスタンス」になく、新しい「メモリ・ロケーション」にデータをコピーしません。インスタンスは同じままであるが、新しいメモリ位置を指します。
編集 FYI:作成中に指定されていない場合のStringBuilderのデフォルト容量は16です。
あなたはStringBuilderのためのメモリ位置を見たい場合は、あなたはあなたのアプリケーションをデバッグし、デバッグ> Windowsの>メモリを使用してメモリをチェックすることができます。追加stmtは実行時にあなたが実際にあなたのStringBuilderに保存されている一人ひとりのバイトのアドレスを見ることができます。
あなたが場所をプログラムこのリンクを取得する必要がある場合は、役立つかもしれません。
それがないので、私たちは本当に、そのStringBuilderの作品をテストしているが、あなた自身の楽しみのために、あなたは常にユニットテストを書くことができないこと。
StringBuilder sb = new StringBuilder(10);
Console.WriteLine("Capacity = " + sb.Capacity + " Length = " + sb.Length
+ " MaxCapacity = " + sb.MaxCapacity);
sb.Append("1234567890");
sb.Append("1234567890");
sb.Append("1234567890");
Console.WriteLine("Capacity = " + sb.Capacity + " Length = " + sb.Length
+ " MaxCapacity = " + sb.MaxCapacity);
Assert.AreEqual("123456789012345678901234567890"
, sb.ToString()); // NUnit assert.
当然のことながら、それは通過し、次の出力が与えられる。
Capacity = 10 Length = 0 MaxCapacity = 2147483647 Capacity = 40 Length = 30 MaxCapacity = 2147483647
のStringBuilderが必要そのバッファを増加する方法は、StringBuilderの内部コードによって考慮されているものです。それはあなたのアプリケーションのILコードで表示されません。それは時々変わることができるので、コンパイラは、特定の方法でのStringBuilderが含まれていますどのように大きな文字列を知ることができません。
StringBuilderのは、ののそのバッファを増やしない場合、しかし、それは新しいStringBuilderのインスタンスにはなりません。それは(私が起こるまさに言ってクラスの内部の仕組みを十分に知っていない)新しいインスタンスを保持している文字列の内部表現をコピーし、それをもたらすことができる。
あなたはかなりのStringBuilderがどのように動作するかを確認するために反射板を使用することができます。
を参照してください方法
StringBuilder Append(string value)
.NET 3.5ロジックについてはこれです:バッファ長が新しい文字列のために十分でない場合、MAX(oldSize新しい* 2、requiredSize)に等しい長さを持つ新しいバッファを作成する
。つまり、StringBufferのバッファを倍増しようとすると、それが十分でない場合は、新しい文字列に合わせてバッファサイズがちょうど十分になります。
古いバッファへの参照が削除されると、古いバッファは、次のガベージコレクションで回収されます。
class Program
{
static void Main()
{
StringBuilder sb = new StringBuilder();
Console.WriteLine(sb.Capacity); //16
for (int i = 0; i < 50; i++)
sb.Append(i + ",");
Console.WriteLine(sb.Capacity); //256
sb = new StringBuilder();
Console.WriteLine(sb.Capacity); //16
}
}