2009-05-19 17 views
2

Ich habe eine Testanwendung zum Testen erstellt, StringBuilder kopiert Daten in eine andere Instanz und vergrößert den Puffer, wenn seine Länge größer ist als die aktuelle Kapazität und in ildasm.exe überprüft wird, aber es scheint identisch zu sein.StringBuilder und Kapazität?

Wie kann überprüft werden, dass StringBuilder seine Daten in eine neue Instanz kopiert und den Puffer um das angegebene Limit erweitert?

Antwort

5

Wenn Sie überprüfen möchten, wie StringBuilder implementiert ist, starten Sie den Reflektor einfach und sehen Sie sich ihn an. Die Implementierung für StringBuilder.Append(string) ist als

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

Blick auf den Abschnitt folgt mit NeedsAllocation, GetNewString und so weiter zu finden, was Sie suchen.

2

Die Art und Weise, wie der StringBuilder seinen Puffer bei Bedarf erhöht, wird durch den internen Code des StringBuilders sichergestellt. Es wird nicht im IL-Code Ihrer Anwendung angezeigt. Der Compiler kann nicht wissen, wie große Strings der StringBuilder in einer bestimmten Methode enthalten wird, da dies von Zeit zu Zeit variieren kann. Wenn der StringBuilder jedoch seinen Puffer erhöht, führt dies nicht zu einer neuen StringBuilder-Instanz Es kann dazu führen, dass es die interne Darstellung der Zeichenfolge, die es enthält, in eine neue Instanz kopiert (ich weiß nicht genug über die inneren Abläufe der Klasse, um genau zu sagen, was passiert).

11

Kapazität repräsentiert den zusammenhängenden Speicher, der dem StringBuilder zugewiesen ist. Kapazität kann> = Länge der Zeichenfolge sein. Wenn mehr Daten an den StringBuilder als die Kapazität angehängt werden, erhöht StringBuilder automatisch die Kapazität. Da die Kapazität überschritten wurde (dh der zusammenhängende Speicher ist voll und es ist kein Pufferspeicher mehr verfügbar), wird ein größerer Pufferbereich zugewiesen, und Daten werden vom ursprünglichen Speicher in diesen neuen Bereich kopiert.

Es werden keine Daten in eine neue 'Instanz' kopiert, sondern in einen neuen 'Speicherort'. Die Instanz bleibt gleich, zeigt aber auf den neuen Speicherort.

bearbeiten FYI: Standardkapazität von String wenn nicht bei der Erstellung angegeben ist 16

Wenn Sie möchten, die Speicherplätze für String sehen, dann können Sie Ihre Anwendungen debuggen und überprüfen Sie den Speicher Debug mit> Fenster> Speicher. Sie können tatsächlich die Adresse jedes einzelnen Bytes sehen, das in Ihrem StringBuilder gespeichert ist, wenn Append stmt ausgeführt wird.

Wenn Sie die Standorte programmatisch bekommen müssen this link könnte helfen.

+0

Gute Antwort. Ich bin neugierig auf den Parameter 'maxCapacity'. Unterscheidet es sich auch konzeptionell von der maximalen Länge aufgrund möglicher Fragmentierung? Was passiert, wenn ich über die Kapazität gehe? Wenn es so funktioniert, wie ich es erwarten würde, dann könnte ich diese Klasse verwenden, um eine Befehlszeile zu erstellen, die von einer ausführbaren Datei ausgeführt wird, die die Länge der Argumente begrenzt. –

+0

über [MSDN] (http://msdn.microsoft.com/en-US/library/system.text.stringbuilder.maxcapacity (v = vs.80) .aspx): Die maximale Kapazität für diese Implementierung ist Int32.MaxValue . Dieser Wert ist jedoch implementierungsspezifisch und kann sich in anderen oder späteren Implementierungen unterscheiden – poncha

5

Nicht, dass wir wirklich testen, dass StringBuilder funktioniert, weil es tut, aber zu Ihrem eigenen Vergnügen können Sie immer einen Komponententest schreiben.

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("123456789" 
     , sb.ToString()); // NUnit assert. 

Es überrascht nicht, es passiert, und die folgende Ausgabe wird angegeben.

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

Sie können Reflector verwenden, um zu sehen, wie StringBuilder funktioniert.

Siehe Methode

StringBuilder Append(string value) 

Für .Net 3.5 Logik ist: Wenn Pufferlänge für die neue Zeichenfolge nicht genug ist, mit einer Länge von neuen Puffer schaffen gleich Max (oldSize * 2, RequiredSize).

Mit anderen Worten, StringBuffer versucht, den Puffer zu verdoppeln, und wenn das nicht genug ist, macht Puffergröße gerade genug, um die neue Zeichenfolge zu passen.

Verweis auf den alten Puffer wird entfernt und der alte Puffer wird mit der nächsten Speicherbereinigung zurückgewonnen.

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