我已经创建了测试应用程序来测试,Is StringBuilder将数据复制到另一个实例并在其长度超过当前容量时增长缓冲区并在ildasm.exe中验证但它看起来完全相同.
如何验证StringBuilder会将其数据复制到新实例并按指定的限制增长缓冲区?
Ras*_*dit 11
Capacity表示分配给StringBuilder的连续内存.容量可以> =字符串的长度.当StringBuilder附加的数据多于容量时,StringBuilder会自动增加容量.由于容量已超过(即连续内存已填满且没有更多缓冲区可用),因此会分配更大的缓冲区,并将数据从原始内存复制到此新区域.
它不会将数据复制到新的"实例",而是复制到新的"内存位置".实例保持不变但指向新的内存位置.
编辑FYI:如果在创建期间未指定,则StringBuilder的默认容量为16
如果您想查看StringBuilder的内存位置,那么您可以使用Debug> Windows> Memory调试应用程序并检查内存.实际上,当Append 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.
Run Code Online (Sandbox Code Playgroud)
不出所料,它通过了,并给出了以下输出.
Capacity = 10 Length = 0 MaxCapacity = 2147483647
Capacity = 40 Length = 30 MaxCapacity = 2147483647
如果要检查StringBuilder的实现方式,只需启动Reflector并查看它.实施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;
}
Run Code Online (Sandbox Code Playgroud)
查看该部分NeedsAllocation,GetNewString依此类推,找到您要找的内容.