C# StringBuilder和容量?

C# StringBuilder和容量?,c#,stringbuilder,C#,Stringbuilder,我已经创建了测试应用程序来测试,是StringBuilder将数据复制到另一个实例,并在其长度超过当前容量时增加缓冲区,并在ildasm.exe中进行验证,但看起来完全相同 如何验证StringBuilder是否会将其数据复制到新实例中,并按指定的限制增加缓冲区?StringBuilder在需要时增加缓冲区的方式由StringBuilder的内部代码负责;它不会显示在应用程序的IL代码中;编译器无法知道特定方法中的StringBuilder将包含多大字符串,因为这可能会随时间而变化 但是,当St

我已经创建了测试应用程序来测试,是StringBuilder将数据复制到另一个实例,并在其长度超过当前容量时增加缓冲区,并在ildasm.exe中进行验证,但看起来完全相同


如何验证StringBuilder是否会将其数据复制到新实例中,并按指定的限制增加缓冲区?

StringBuilder在需要时增加缓冲区的方式由StringBuilder的内部代码负责;它不会显示在应用程序的IL代码中;编译器无法知道特定方法中的StringBuilder将包含多大字符串,因为这可能会随时间而变化


但是,当StringBuilder增加其缓冲区时,不会产生新的StringBuilder实例。这可能会导致它将其持有的字符串的内部表示形式复制到一个新实例(我对类的内部工作机制了解不够,无法确切说明发生了什么)。

容量表示分配给StringBuilder的连续内存。容量可以大于等于字符串的长度。当附加到StringBuilder的数据多于容量时,StringBuilder会自动增加容量。由于容量已超过(即连续内存已满且没有更多可用的缓冲空间),因此会分配更大的缓冲区,并将数据从原始内存复制到此新区域

它不会将数据复制到新的“实例”,而是复制到新的“内存位置”。实例保持不变,但指向新的内存位置

编辑 仅供参考:如果在创建期间未指定,StringBuilder的默认容量为16

如果您想查看StringBuilder的内存位置,则可以调试应用程序并使用“调试>窗口>内存”检查内存。当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.
毫不奇怪,它通过了,并给出了以下输出

Capacity = 10 Length = 0 MaxCapacity = 2147483647 Capacity = 40 Length = 30 MaxCapacity = 2147483647 容量=10长度=0最大容量=2147483647 容量=40长度=30最大容量=2147483647
您可以使用Reflector了解StringBuilder的工作原理

见方法

StringBuilder Append(string value)
对于.Net 3.5,逻辑是这样的:如果缓冲区长度不足以容纳新字符串,则创建长度等于Max(oldSize*2,requiredSize)的新缓冲区

换句话说,StringBuffer尝试将缓冲区加倍,如果这还不够,则使缓冲区大小刚好适合新字符串


对旧缓冲区的引用将被删除,旧缓冲区将在下一次垃圾回收时被回收。

如果您想检查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;
}
查看包含
NeedsAllocation
GetNewString
等内容的部分,找到您要查找的内容。

课程计划
 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
        }
    }
{ 静态void Main() { StringBuilder sb=新的StringBuilder(); 控制台写入线(某人容量);//16 对于(int i=0;i<50;i++) sb.附加(i+“,”); 控制台写入线(某人容量);//256 sb=新的StringBuilder(); 控制台写入线(某人容量);//16 } }
回答得好。我对
maxCapacity
参数很好奇。由于潜在的碎片,它在概念上是否也不同于最大长度?当我超过容量时会发生什么?如果它按照我期望的方式工作,那么我可以使用这个类构建一个命令行字符串,由某个对参数长度有限制的可执行文件执行。via:这个实现的最大容量是Int32.MaxValue。但是,此值是特定于实现的,在其他或更高的实现中可能会有所不同