StringBuilder sb = new StringBuilder("test", 4);
sb.Append('\n');
sb.AppendLine("test1");
sb.AppendLine("test2");
sb.AppendLine("test3");
sb.AppendLine("test4");
Run Code Online (Sandbox Code Playgroud)
looking on IL code there is only one newobj line, but I thought there should be more instances of StringBuilder class since it should increase its capacity by creating new object? Or I got it wrong?
// [3 1 - 3 49]
IL_0000: ldstr "test"
IL_0005: ldc.i4.4
IL_0006: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor(string, int32)
IL_000b: stloc.0 // sb
// [4 1 - 4 17]
IL_000c: ldloc.0 // sb
IL_000d: ldc.i4.s 10 // 0x0a
IL_000f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(char)
IL_0014: pop
// [5 1 - 5 24]
IL_0015: ldloc.0 // sb
IL_0016: ldstr "test1"
IL_001b: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::AppendLine(string)
IL_0020: pop
// [6 1 - 6 24]
IL_0021: ldloc.0 // sb
IL_0022: ldstr "test2"
IL_0027: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::AppendLine(string)
IL_002c: pop
// [7 1 - 7 24]
IL_002d: ldloc.0 // sb
IL_002e: ldstr "test3"
IL_0033: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::AppendLine(string)
IL_0038: pop
// [8 1 - 8 24]
IL_0039: ldloc.0 // sb
IL_003a: ldstr "test4"
IL_003f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::AppendLine(string)
IL_0044: pop
IL_0045: ret
Run Code Online (Sandbox Code Playgroud)
from Troelsen book about c#, translated paragraph by me: "If you add more characters than the specified limit, the StringBuilder object will copy its data to a new instance and increase the buffer size by the specified limit."
Asked a friend to provide original quote, here it is, page 89 "Pro C#10 with .Net 6":
If you append more characters than the specified limit, the StringBuilder object will copy its data into a new instance and grow the buffer by the specified limit.
查看您自己的 C# 代码的 IL 不会告诉您有关内部StringBuilder执行的任何信息,而这正是本书所讨论的内容。您需要查看的源代码或其 IL 才能看到这一点。StringBuilder
的文档StringBuilder仅提到“新缓冲区”或“分配新内存”,而从未具体提及“新实例StringBuilder”。
如果有可用空间,则将新数据追加到缓冲区;否则,分配一个新的、更大的缓冲区,将原始缓冲区中的数据复制到新缓冲区,然后将新数据附加到新缓冲区。
如果添加的字符数导致
StringBuilder对象的长度超过其当前容量,则分配新的内存,Capacity属性的值加倍,向对象添加新的字符StringBuilder,并Length调整其属性。
因此,是否创建StringBuilders 的新实例是一个实现细节。查看source.dot.net,它确实在ExpandByABlock.
// Allocate the array before updating any state to avoid leaving inconsistent state behind in case of out of memory exception
char[] chunkChars = GC.AllocateUninitializedArray<char>(newBlockLength);
// Move all of the data from this chunk to a new one, via a few O(1) reference adjustments.
// Then, have this chunk point to the new one as its predecessor.
m_ChunkPrevious = new StringBuilder(this);
m_ChunkOffset += m_ChunkLength;
m_ChunkLength = 0;
m_ChunkChars = chunkChars;
Run Code Online (Sandbox Code Playgroud)
在此实现中,StringBuilder被实现为链表。实例StringBuilder是节点。上面的代码基本上将前一个节点设置为 的副本this,并创建this一个容量为 的“空”节点newBlockLength。