我已经创建了测试应用程序进行测试,是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> Memory检查内存。实际上,当附加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 Append(string value)

对于.NET 3.5逻辑是:如果缓冲区长度不足以适合新字符串,请创建与最大长度等于最大的新缓冲区(oldsize * 2,sircessize)。

换句话说,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
        }
    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top