2009-07-02 1 views
3

StringBuilderタイプには制限があり(デフォルトは16文字)、制限を超えていくつかのテキストを追加すると、上限が設定された新しいインスタンスが作成されますデータがコピーされます。System.Text.StringBuilder limit

StringBuilder test = new StringBuilder("ABCDEFGHIJKLMNOP",16); 
test.Append("ABC"); 

そして、そのために生成さCILだった:私は、次のコードを使用することを試みた

制限を設定
.maxstack 3 
    .locals init (class [mscorlib]System.Text.StringBuilder V_0) 
    IL_0000: nop 
    IL_0001: ldstr  "ABCDEFGHIJKLMNOP" 
    IL_0006: ldc.i4.s 16 
    IL_0008: newobj  instance void [mscorlib]System.Text.StringBuilder::.ctor(string, int32) 
    IL_000d: stloc.0 
    IL_000e: ldloc.0 
    IL_000f: ldstr  "ABC" 
    IL_0014: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string) 
    IL_0019: pop 
    IL_001a: ret 

32、たとえば、に:

StringBuilder test = new StringBuilder("ABCDEFGHIJKLMNOP",32); 
test.Append("ABC"); 
まったく同じ生成

ILコード。 私が期待することは、最初のケースで新しいインスタンスを作成し、2番目のケースでインスタンスの値を変更することです。これは明らかに起こりませんでした。あなたはAppend()メソッドへの呼び出しを行う場所です

IL_0014: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string) 

、しかし、あなたが投稿したILは、そのメソッドの本体が含まれていません:

答えて

8

すべての楽しさのものは、この行で発生します。 source codeでは、StringBuilderクラス(それはあなたが見ることができるライセンスの下でリリースされています)を見て、Append()メソッド内で何が起こるかを見てください。

スポイラー警告!ソースコードAppend()を見ると、連結された文字列の長さがバッファの現在のサイズを超えるたびに内部バッファが実際に増加することがわかります。

+0

しかし、結果のCILコードでは、文字列を操作するときに新しい文字列が作成されるのと同じように、CILコードを理解すると、新しい文字列ビルダが作成されます。 –

+0

あなたが何を意味するか分かりません - ILのどこを探していますか?私は、コンストラクタ(IL_0008)への呼び出しとAppend()メソッド(IL_0008)への呼び出しの両方を見るだけです。これはあなたのC#コードをよく反映しているようです。 –

+1

いいえ、新しいstringbuilderオブジェクトは作成されません。既存のstringbuilderは新しいBUFFERを割り当てます。 –

2

StringBuilderには、ほとんどのコレクションクラスと同様に、Capacityプロパティがあります。コレクションが容量を超えて大きくなると、内部データ構造(オブジェクト自体ではない)が再割り当てされ、倍増戦略を使用するほとんどの場合(私はStringBuilderとList <>について確信しています)そして、はい、それは新しい配列の作成と古いデータのコピーを伴います。高い見積もりを取り、そしておそらくいくつかの余分なスペースを追加するには悪いアイデアではありません

var sb = new StringBuilder(n); // set initial Capacity=n 

:あなたはendresultがあることを行っているどのように大きなに関する情報を持っている場合は

は、のようなものを使用します。いくつかの文字をあまりにも多く割り当てて、それを途中でコピーする方がよい。

これは自動的に拡大することができるコレクション(StringBuilderはcharのコレクションのようなもの)を持つために支払う代金です。ブロックのリンクされたリストのような選択肢が複雑に見えると思います。

+0

内部データ構造(オブジェクト自体ではなく)が再割り当てされる方法をもっと明確にしてください、ありがとうございます。 –

+0

StringBuilderは、テキストを保持するために内部ストレージを必要とします。char [] text = new char [Capacity] 実際のStringBuilderを再作成した場合、オブジェクトへの参照をすべて更新することはできません。大混乱を招くようなもの。 –

+1

配列を保持するクラスレベルの変数を持つクラスを考えてください。この変数に格納されている配列を、クラスのインスタンスを変更せずに別の配列インスタンスに置き換えることはできますか?もちろんできます! –

1

ILコードを誤解していると思います。

IL_0014: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string) 

...というのは、新しいStringBuilderインスタンスが作成されたことを意味するものではありません。それは単にAppendメソッドへの呼び出しです。

Appendを呼び出すことStringBuilderの電流容量よりも長い文字列につながる場合、それは新しいStringインスタンスを作成します内部。依然として同じStringBuilderインスタンスになります。

+0

新しい文字列インスタンスが内部的にどのように作成されているか、私は非常に興味があります。 –

+0

今私は、ジョエルミューラーのおかげでそれを理解します。 –

3

このC#コードは

using System.Text; 

internal class Program 
{ 
    internal static void Main(string[] args) 
    { 
     StringBuilder test = new StringBuilder("ABCDEFGHIJKLMNOP", 16); 
     test.Append("ABC"); 

     StringBuilder test2 = new StringBuilder("ABCDEFGHIJKLMNOP", 32); 
     test2.Append("ABC"); 
    } 
} 

(リフレクターに応じて)次ILを生成します。

.class private auto ansi beforefieldinit Program 
    extends [mscorlib]System.Object 
{ 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
     .maxstack 8 
     L_0000: ldarg.0 
     L_0001: call instance void [mscorlib]System.Object::.ctor() 
     L_0006: ret 
    } 

    .method assembly hidebysig static void Main(string[] args) cil managed 
    { 
     .entrypoint 
     .maxstack 3 
     .locals init (
      [0] class [mscorlib]System.Text.StringBuilder test, 
      [1] class [mscorlib]System.Text.StringBuilder test2) 
     L_0000: nop 
     L_0001: ldstr "ABCDEFGHIJKLMNOP" 
     L_0006: ldc.i4.s 0x10 
     L_0008: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor(string, int32) 
     L_000d: stloc.0 
     L_000e: ldloc.0 
     L_000f: ldstr "ABC" 
     L_0014: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string) 
     L_0019: pop 
     L_001a: ldstr "ABCDEFGHIJKLMNOP" 
     L_001f: ldc.i4.s 0x20 
     L_0021: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor(string, int32) 
     L_0026: stloc.1 
     L_0027: ldloc.1 
     L_0028: ldstr "ABC" 
     L_002d: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string) 
     L_0032: pop 
     L_0033: ret 
    } 
} 
だからここ

0x100x20testtest2をinitalizeするために使用されている、あなたはおそらく見えたことを意味しますあなたのテストで間違ったILで?

+0

ありがとう! "ldc.i4.s 0x10/0x20"とはどういう意味ですか? –

+0

0x20(hex)= 32 dez、0x10(hex)= 16 dez :) 私はILにはあまり慣れていませんが、それは16進数で設定されたコンストラクタパラメータだと思います。 – hangy

+0

OK、ありがとう:) –