Der beste Weg, um Inhalte von .NETs StringBuilder zu löschen

74

Ich möchte fragen, was Ihrer Meinung nach der beste Weg ist (weniger hält / weniger Ressourcen verbraucht), um den Inhalt zu löschen und einen StringBuilder wiederzuverwenden. Stellen Sie sich folgendes Szenario vor:

StringBuilder sb = new StringBuilder();
foreach(var whatever in whateverlist)
{
  sb.Append("{0}", whatever);
}

//Perform some stuff with sb

//Clear stringbuilder here

//Populate stringbuilder again to perform more actions
foreach(var whatever2 in whateverlist2)
{
  sb.Append("{0}", whatever2);
}

Und wenn ich StringBuilder lösche, kann ich mir zwei Möglichkeiten vorstellen:

sb = new StringBuilder();

oder

sb.Length = 0;

Was ist der beste Weg, um es zu klären und warum?

Vielen Dank.

BEARBEITEN: Ich erwähne mit der aktuellen .NET 3.5-Version.

David Espart
quelle
4
Keine Antwort, aber interessant zu lesen: bobondevelopment.com/2007/06/11/…
Philip Wallace
1
Was ist der Grund dafür, dass die StringBuilder.Clear () -Methode nicht als Alternative aufgenommen wurde?
Rune FS
@ Run: c # 4.0 ist noch nicht raus, es ist nur in 4.0. Auf MSDN heißt es: Unterstützt in: 4.
jcollum
Glück für mich, dass c # 4.0 aus blogs.msdn.com/somasegar/default.aspx
Rune FS
2
Ich frage mich, warum Lengthes beschreibbar ist, aber es gibt keine Lese- / Schreib-Eigenschaft "Text". Das zu sagen sb.Text = "";scheint klarer zu sein sb.Length = 0;, und eine TextEigenschaft würde auch in dem üblichen Szenario helfen, in dem man sonst etwas sagen müsste sb.Length = 0; sb.Append(StuffToStartWith);.
Supercat

Antworten:

71

Wenn Sie dies in .NET 2.0 oder 3.5 tun, schreiben Sie eine Erweiterungsmethode, um dies wie folgt zu tun:

/// <summary>
///     Clears the contents of the string builder.
/// </summary>
/// <param name="value">
///     The <see cref="StringBuilder"/> to clear.
/// </param>
public static void Clear(this StringBuilder value)
{
    value.Length = 0;
    value.Capacity = 0;
}

Dann können Sie es wie folgt löschen:

someStringBuilder.Clear();

Wenn dann 4.0 herauskommt, können Sie Ihre Erweiterungsmethode zugunsten der 4.0-Version fallen lassen.

UPDATE : Es ist wahrscheinlich keine gute Idee, die Kapazität auf Null zu setzen. Dies garantiert eine Neuzuweisung, wenn Sie an den Builder anhängen, wenn Sie dieselbe Instanz wiederverwenden. Der Speicher in der Instanz des Builders wird jedoch erst freigegeben, wenn Sie die Kapazität auf einen sehr kleinen Wert (z. B. 1) festgelegt haben. Der Standardwert der Capacity-Eigenschaft ist 16. Möglicherweise möchten Sie 16 verwenden oder (obwohl dies weniger effizient ist) die Kapazität zweimal einstellen:

  • Setzen Sie es auf 1 oder Null, um den Speicher zu löschen
  • Stellen Sie den ursprünglichen Kapazitätswert (der von 16 abweichen kann) ein, um ihn wiederherzustellen.
Mike Hofer
quelle
Ordentliche Methode. Genau das, wonach ich gesucht habe.
Abhi
15
Ich würde empfehlen, die Kapazität nicht zu löschen, es sei denn, es StringBuilderist bekannt, dass sie etwas ungewöhnlich Großes enthält. Insbesondere in früheren Versionen von .net führt das Löschen des Puffers nach jeder Zeichenfolge dazu, dass jedes Mal, wenn der Puffer neu wachsen muss, zusätzliche Objekte im Heap für große Objekte zugewiesen werden, wenn wiederholt Zeichenfolgen mit mehr als 42.500 Zeichen erstellt werden. Das ist eine schlechte Sache.
Supercat
2
Das Setzen der Kapazität auf 0 ist eine interessante Idee. Wenn Sie nur Clear verwenden oder nur die Länge auf 0 setzen, kann ein Speicherverlust auftreten, wenn Insert () wiederholt verwendet wird, da die Kapazität trotz Clear weiter wächst. (siehe meine Frage: stackoverflow.com/questions/29574469/…
Peter Huber
29

In .NET 4.0 können Sie aufrufen sb.Clear(), in älteren Versionen sollten Sie jedoch festlegen sb.Length = 0.

Die Clear()Methode wurde in .NET 4.0 hinzugefügt.

GraemeF
quelle
15
Wenn Sie es wiederverwenden, möchten Sie den Puffer dann nicht wiederverwenden?
GraemeF
2
hängt von der Varianz ab, wie groß die Zeichenfolge beim ersten Mal im Vergleich zur Zeichenfolge beim zweiten Mal ist. Oder zumindest würde ich das glauben
Earlz
16

Erstellen Sie den neuen StringBuilder. Der alte verwaltet die damit verbundenen Ressourcen (z. B. Puffer mit maximaler Länge), die am besten nur den gesammelten Müll sind.

Paul Sonier
quelle
11

Ich denke, Sie führen eine vorzeitige Optimierung durch.

Ich würde wetten, dass sb.Length=0;es am schnellsten ist, ein anderes Objekt zu erstellen und ein anderes Objekt beiseite zu legen, damit GC es schließlich sammeln kann.

Ich denke, das Erstellen eines neuen StringBuilder wäre die beste Lösung für Speicherprobleme. und Einstellung sb.Lengthwäre der beste Schuss für Geschwindigkeitsprobleme ..

Earlz
quelle
11

Aus Community-Inhalten auf MSDN :

Um Ihren Stringbuilder effektiv zu löschen, ohne ihn zu zerstören, verwenden Sie:

 someStringBuilder.length = 0;
 someStringBuilder.capacity = 0;

Dies zerstört sowohl den Inhalt als auch die Größe auf Null. Wie oben erwähnt, kann die Größe kleinere Anwendungen beeinflussen.

Yuriy Faktorovich
quelle
5

In .NET Framework 4 wurden neue Methoden in der StringBuilderKlasse eingeführt. Der Methodenname lautet "Clear". Mit dieser Methode können Sie Werte oder Daten von StringBuilderObjekten löschen oder entfernen .

Hier ist ein Beispiel dafür.

    System.Text.StringBuilder objSB = new System.Text.StringBuilder();
    //Append values
    objSB.Append("This is .Net Blog.");
    objSB.Append("You can get latest C# Tips over here.");

    //Display on screen
    Response.Write(objSB.ToString());
    Response.Write("<br/><br/>");

    //Clear object using Clear method
    objSB.Clear();

    //Append another values
    objSB.Append("This blog is very useful for .Net Beginners");

    Response.Write("After Clear<br/><br/>");
    //Display on screen
    Response.Write(objSB.ToString());
Jayesh Sorathia
quelle
2

Wenn Sie die Speichernutzung reduzieren möchten, würde ich den CLR-Profiler verwenden, um mithilfe der oben beschriebenen Methoden zu überprüfen, wie viel Speicher Ihre StringBuilder-Objekte während ihres Lebenszyklus verwenden. Dann können Sie sich davon überzeugen, dass die von Ihnen gewählte Option für Ihre Bedürfnisse geeignet ist und die Ressourcen freigibt, für die Sie sie benötigen.

Kim R.
quelle
1

Ich würde sagen, der beste Weg, dies zu klären, ist die Verwendung sb = new StringBuilder();. Abgesehen davon denke ich, dass es noch besser wäre, wenn Sie ein neues String Builder-Objekt erstellen würden.

BEARBEITEN

Ich hoffe, es versteht sich von selbst, dass dies die beste Lösung ist.

public StringBuilder MakeString(IEnumerable<CoolType> list)
{
    StringBuilder sb = new StringBuilder();

    foreach(var whatever in list)
    {
        sb.Append("{0}", whatever);
    }
}

var sb = MakeString(whateverList);
// Do stuff
// Clear stuff
sb = MakeString(whateverList2);
Matt Grande
quelle
5
sb = new StringBuilder () erstellt ein neues String Builder-Objekt.
Philip Wallace
Wenn Sie dies tun, wird ein neues String Builder-Objekt erstellt.
Paul Sonier
Ich denke, Matt bedeutet, eine neue Variable für die neue zu deklarieren StringBuilder.
Dan Tao
Entschuldigung, um zu klären, empfehle ich Folgendes: var wellNamedStringBuilder = new StringBuilder ();
Matt Grande
0

Rufen Sie einfach die Clear () -Methode auf und setzen Sie einfach die Länge = 0. Wir können auch die Kapazität = 0 setzen, wenn wir Speicher sparen möchten

public StringBuilder Clear() {
        this.Length = 0;
        return this;
 }

Ref: In referencesource.microsoft.com

Max CHien
quelle
0
// P.S. to be ultra efficient 
// make a good guess at the initial allocation too !!!!
int PerWhatever_SizeEstimate = 4; // a guess of average length... you known your data
StringBuilder sb = new StringBuilder( whateverlist.Length * PerWhatever_SizeEstimate);

// reallocation needed? 
// if you want to be efficient speed and memory wise... 
sb.Length = 0;  // rest internal index but don't release/resize memory
// if a ...BIG... difference in size
if( whatever2.Length < whatever.Length * 2/3  
 || whatever2.Length > whatever.Length * 1.5)
{
    //scale capacity appropriately
    sb.Capaciy = sb.Capacity * whatever2.Length / whatever.Length;
}
PJJ
quelle
0

C # Auf den Punkt gebracht Um den Inhalt von a zu löschen StringBuilder, gibt es zwei Möglichkeiten:

  1. Setzen Sie es Lengthauf Null:

    Wenn Sie einen StringBuilder so einstellen Length, zerodass er seine interne Kapazität nicht verringert. Wenn der StringBuilder zuvor eine Million Zeichen enthielt, belegt er nach dem Nullstellen seiner Länge weiterhin etwa 2 MB Speicher.

  2. Instanziieren Sie eine neue:

    Wenn Sie möchten release the memory, müssen Sie einen neuen StringBuilder erstellen und dem alten erlauben, den Gültigkeitsbereich zu verlassen (und Müll zu sammeln). Mit diesem Ansatz können Sie das vorherige Elementproblem lösen.

Sina Lotfi
quelle