C# StringBuilder 和容量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/880990/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:12:29  来源:igfitidea点击:

StringBuilder and capacity?

c#stringbuilder

提问by Anonymous

I have created test application to test, Is StringBuilder copy data to another instance and grow it buffer when its length is more than current capacity and verify in ildasm.exe but it seem identical.

我创建了测试应用程序来测试,StringBuilder 是否将数据复制到另一个实例并在其长度超过当前容量时增加缓冲区并在 ildasm.exe 中验证,但它似乎相同。

How to verify StringBuilder will copy its data into new instance and grow the buffer by the specified limit?

如何验证 StringBuilder 将其数据复制到新实例并按指定限制增长缓冲区?

采纳答案by Brian Rasmussen

If you want to inspect how StringBuilder is implemented, just fire up Reflector and look at it. The implementation for StringBuilder.Append(string)is as follows

如果您想检查 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;
}

Look at the section with NeedsAllocation, GetNewStringand so forth to find what you're looking for.

查看带有NeedsAllocation,GetNewString等的部分以找到您要查找的内容。

回答by Fredrik M?rk

The way that the StringBuilder increases its buffer when needed is something that is taken care of by the internal code of the StringBuilder; it will not show in the IL code of your application; the compiler cannot know how large strings the StringBuilder in a certain method will contain, since that can vary from time to time.

StringBuilder 在需要时增加其缓冲区的方式是由 StringBuilder 的内部代码处理的;它不会显示在您的应用程序的 IL 代码中;编译器无法知道某个方法中的 StringBuilder 将包含多大的字符串,因为它会不时变化。

However, when the StringBuilder doesincrease its buffer, it will not result in a new StringBuilder instance. It may result in it copying the internal representation of the string that it holds to a new instance (I don't know enough of the inner workings of the class to say exactly what happens).

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

回答by SO User

Capacity represents the contiguous memory allocated to the StringBuilder. Capacity can be >= length of the string. When more data is appended to the StringBuilder than the capacity, StringBuilder automatically increases the capacity. Since the capacity has exceeded (that is contiguous memory is filled up and no more buffer room is available), a larger buffer area is allocated and data is copied from the original memory to this new area.

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

It does not copy data to new 'instance' but to new 'memory location'. The instance remains the same but points to the new memory location.

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

Edit FYI: Default capacity of StringBuilder if not specified during creation is 16

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

If you wanna see the memory locations for StringBuilder then you can debug your applications and check the memory using Debug > Windows > Memory. You can actually see the address of each and every byte stored in your StringBuilder when Append stmt runs.

如果您想查看 StringBuilder 的内存位置,那么您可以调试您的应用程序并使用 Debug > Windows > Memory 检查内存。当 Append stmt 运行时,您实际上可以看到存储在 StringBuilder 中的每个字节的地址。

If you need to get the locations programatically this linkmight help.

如果您需要以编程方式获取位置,此链接可能会有所帮助。

回答by Robert Paulson

Not that we're really testing that StringBuilder works, because it does, but for your own enjoyment you can always write a unit test.

并不是说我们真的在测试 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.

Unsurprisingly, it passes, and the following output is given.

不出所料,它通过了,并给出了以下输出。

    Capacity = 10 Length = 0 MaxCapacity = 2147483647
    Capacity = 40 Length = 30 MaxCapacity = 2147483647

回答by Konstantin Spirin

You can use Reflector to see pretty much how StringBuilder works.

您可以使用 Reflector 来了解 StringBuilder 的工作原理。

See method

见方法

StringBuilder Append(string value)

For .Net 3.5 logic is this: if buffer length is not enough for the new string, create new buffer with length equal to Max(oldSize * 2, requiredSize).

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

In other words, StringBuffer tries to double the buffer and if that is not enough then makes buffer size just enough to fit the new string.

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

Reference to the old buffer gets removed and the old buffer gets reclaimed with the next garbage collection.

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

回答by lukaszk

 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
        }
    }