2010-02-15 8 views
6

Ich frage mich, wenn dieser Code ...Enthält ein mit einer Zeichenfolge initialisierter StringBuilder genau (nur) genügend Speicherplatz für diese Zeichenfolge?

StringBuilder sb = new StringBuilder("Please read the following messages."); 

... sb mit einem Puffer initialisiert genau so groß wie die Zeichenfolge an den Konstruktor übergeben. Auf der einen Seite scheint dies das logischste zu sein. Auf der anderen Seite scheint es den Zweck der StringBuilder-Klasse für eine ihrer häufigsten Anwendungen zu besiegen, nämlich Mutabilität bereitzustellen, um wiederholte Attends effizienter zu machen. (Der erste Aufruf Append, wenn die Antwort auf meine Frage „Ja“ ist, würde sb verpflichten, sich zu ändern.)

Dann wieder, ich nehme man dies als analog zu den Konstruktor sehen konnte für List<T> dass ein dauert IEnumerable<T> als Parameter. Vielleicht ist die Annahme in diesem Fall, dass Sie nicht planen, auf eine Menge, sondern eher auf manipulieren was schon da ist.

Die einzige wirkliche Forschung, die ich auf das getan habe, war die MSDN documentation on StringBuilder zu überprüfen, die keine Antwort geliefert haben (es sagt der Konstruktor die Instanz initialisiert „die angegebene Zeichenfolge verwendet wird,“ aber zeigt nicht wie die Zeichenfolge wird verwendet).


EDIT: So ist es "Implementierung spezifisch" ... ist das nicht seltsam scheint jemand anderes? Ich meine, der Zweck der StringBuilder Klasse soll eine Alternative zur Durchführung einer Menge von Operationen auf einem string, eine Menge von unveränderlichen string Instanzen auf dem Weg bieten; Daher ist es für Effizienz. Ich habe das Gefühl, dass das Verhalten dieses Konstruktors spezifiziert werden sollte, so dass der Entwickler eine informierte Entscheidung treffen kann, wie er es unabhängig von der Plattform verwenden kann.

Ich meine, es ist ist von Microsoft auf eine bestimmte Weise implementiert; Sie hätten das leicht in die Dokumentation einfügen können (andere Implementierungen müssten folgen). Nur eine persönliche Quelle der Verwirrung ...

Antwort

5

Es ist ein Implementierungsdetail, über das Sie sich keine Sorgen machen sollten.Unter Verwendung von .NET reflector und dem Suchen in der (string, int32, int32, int32) Überladung des Konstruktors (die die anderen Konstruktoren aufrufen) können wir sehen, dass es eine Kapazität auswählt, die ein Vielfaches von 16 ist (nächstgrößer über den angeforderten Größe)

bearbeiten

Eigentlich ist es 16 x 2^n, wobei der Wert von „n“ gewählt, daß der nächstgrößere Größe

+0

Guter Ruf - Ij Das habe ich selbst überprüft und bin zu der gleichen Schlussfolgerung gelangt (indem ich nach der Initialisierung die Eigenschaft 'Capacity' überprüft habe ... irgendwie ist mir das erst aufgefallen, nachdem ich die Frage gepostet hatte). –

+1

... und doch sollten Sie sich nicht darauf verlassen. Wenn Sie sich genügend Gedanken über die erforderliche Kapazität zum Veröffentlichen einer Frage in Stack Overflow machen, sollten Sie nur eine der Überladungen verwenden, in der Sie sie angeben können. Der ganze Zweck von "implementierungsspezifisch" bedeutet, dass es sich in Zukunft ändern kann. Verlassen Sie sich nicht auf undokumentiertes Verhalten. –

+0

@Lasse - Oh, einverstanden. Ich würde nicht befürworten, * sich auf dieses Detail zu verlassen. (Und kämpfen um zu denken, wie Sie sich auf diese Tatsache verlassen könnten) –

4

Überprüfen Sie das Kapazität Mitglied des StringBuilder.

Von MSDN:

Der String dynamisch zuordnet mehr Platz, wenn erforderlich und erhöht dementsprechend Kapazität. Aus Leistungsgründen weist ein StringBuilder möglicherweise mehr Speicher zu als benötigt. Die Menge des zugewiesenen Speichers ist implementierungsspezifisch.

2

der Konstruktor Sie wahrscheinlich die gekettet ist mit seinem StringBuilder(String, Int32, Int32, Int32):

public StringBuilder(
    string value, 
    int startIndex, 
    int length, 
    int capacity 
) 

Also, für die Zeichenfolge würde es wahrscheinlich durchlaufen: string, 0, string.Length, string.Length. Oder etwas ähnliches, das im StringBuilder-Kontext sinnvoll ist.

+0

Klingt wie (aus Damiens Antwort, für die er Reflector verwendet hat), dein erstes "wahrscheinlich" war richtig, und dein zweites war nah dran (eigentlich die nächste Potenz von 16, im Gegensatz zu "string.Length"). –

+0

... und mit "die nächste Potenz von 16" meine ich "16 mal die nächste Potenz von 2". Ich glaube nicht nach 16 geht es direkt auf 256 und dann auf 4096 (ich bin blöd). –

1

Der Konstruktor, der schließlich aufgerufen wird, ist:

// "Please read the following messages.".Length = 35 
public StringBuilder(string value, int startIndex, int length, int capacity) 
public StringBuilder("Please read the following messages.", 0, 
     "Please read the following messages.".Length, 16) 

(Dies ist nichts, was die anderen Antworten nicht bieten, und ist nur aus Reflektor)
Wenn die Kapazität als die Länge weniger ist der Zeichenfolge, die es in diesem Fall:

while (capacity < length) 
{ 
    capacity *= 2; 
    if (capacity < 0) 
    { 
     capacity = length; 
     break; 
    } 
} 

in Mono ordnet der StringBuilder(string val) Konstruktor die Kapazität zu, bis ein int.MaxValue append auftritt.

Die wirkliche Antwort liegt in der Methode, die intern in der CLR genannt endet wird, wobei die Länge der Kapazität ist:

[MethodImpl(MethodImplOptions.InternalCall)] 
private static extern string FastAllocateString(int length); 

Ich kann nicht die Quelle für diese in der SSCLI finden jedoch die Mono-Version (\ Mono \ Metadaten \ object.c) tut es wie folgt aus:

mono_string_new_size (MonoDomain *domain, gint32 len) 
{ 
    MonoString *s; 
    MonoVTable *vtable; 
    size_t size = (sizeof (MonoString) + ((len + 1) * 2)); 

... 
} 

, die die Größe in Bytes eines MonoString Objekt ist, plus die Länge mal 2.

+0

Woher kommen diese Informationen? Verwenden Sie Windows, Mono oder ...? Es scheint, dass Ihre Ergebnisse bezüglich der anfänglichen Kapazität von StringBuilder von denen von Damien (und meins) abweichen. –

+0

@Dan - ein kleiner Fehler mit 0x10 :) –

+0

Der Code, den Sie bereitgestellt haben, ist hilfreich, aber widerspricht dem, was Sie gesagt haben! "Der Konstruktor verwendet die Länge Ihres Strings als Kapazität" - das ist nicht wahr; diese "while" -Schleife verdoppelt die "Kapazität" bis "Kapazität> = Länge"; daher ist es sein Startwert (der 16 zu sein scheint) mal eine Potenz von 2. –

Verwandte Themen