2010-02-15 8 views
6

Mi chiedo se questo codice ...Un StringBuilder inizializzato con una stringa contiene esattamente (solo) spazio sufficiente per quella stringa?

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

... inizializza sb con un buffer esattamente grande come la stringa passata al costruttore. Da un lato, questa sembra la cosa più logica. D'altra parte, sembra di tipo di sconfiggere lo scopo della classe StringBuilder per uno dei suoi usi più comuni, che è quello di fornire la mutevolezza per rendere più efficienti gli allegati ripetuti. (La prima chiamata a Append, se la risposta alla mia domanda è "sì", richiederebbe sb per ridimensionare sé.)

Poi di nuovo, suppongo si potrebbe vedere questa come analogo al costruttore per List<T> che prende un IEnumerable<T> come parametro. Forse l'ipotesi in questo caso è che non stai pianificando su aggiungendo molto, ma piuttosto su manipolando che cosa c'è già.

L'unica vera ricerca che ho fatto su questo è stato quello di verificare l'MSDN documentation on StringBuilder, che non ha fornito una risposta (si dice il costruttore inizializza l'istanza "utilizzando la stringa specificata," ma non indica come la stringa è usata).


EDIT: Quindi è "implementazione-specifico" ... fa questo non sembra strano per chiunque altro? Voglio dire, lo scopo della classe StringBuilder è offrire un'alternativa all'esecuzione di molte operazioni su un string, creando una tonnellata di immutabili string istanze lungo il percorso; pertanto, è per l'efficienza . Ritengo che il comportamento di questo costruttore debba essere specificato, in modo che lo sviluppatore possa prendere una decisione informata su come utilizzarlo indipendentemente dalla piattaforma.

Voglio dire, è è implementato da Microsoft in un certo modo; potevano facilmente averlo messo nella documentazione (costringendo altre implementazioni a seguirne l'esempio). Solo una fonte personale di perplessità ...

risposta

5

È un dettaglio di implementazione di cui non dovresti preoccuparti.Tuttavia, usando .NET reflector e osservando l'overload (string, int32, int32, int32) del costruttore (che gli altri costruttori chiamano), possiamo vedere che seleziona una capacità che è un multiplo di 16 (il prossimo più grande rispetto al richiesto dimensioni)

Modifica

in realtà, è 16 x 2^n, con il valore di "n" selezionato per essere il prossimo grande dimensione

+0

Buon chiamata - I j l'ho controllato io stesso e raggiunto la stessa conclusione (controllando la proprietà 'Capacity' dopo l'inizializzazione ... in qualche modo questo non mi è accaduto fino a dopo aver postato la domanda). –

+1

... eppure non dovresti fare affidamento su questo. Se ti interessa abbastanza della capacità richiesta di pubblicare una domanda su Stack Overflow, dovresti semplicemente usare uno dei sovraccarichi dove puoi specificarlo. L'intero scopo di "implementazione specifica" significa che può cambiare in futuro. Non fare affidamento su comportamenti non documentati. –

+0

@Lasse - Oh, d'accordo. Non vorrei sostenere * basandomi * su questo dettaglio. (E faticando a pensare a come potresti finire per affidarti a questo fatto) –

4

Controllare il membro della Capacità di StringBuilder.

Da MSDN:

Lo StringBuilder alloca dinamicamente più spazio quando richiesto e aumenta la capacità di conseguenza. Per motivi di prestazioni, un oggetto StringBuilder può allocare più memoria del necessario. La quantità di memoria allocata è specifica dell'implementazione.

2

il costruttore si è collegato al probabilmente è incatenato al StringBuilder(String, Int32, Int32, Int32):

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

Quindi, per la stringa, probabilmente passerebbe attraverso: string, 0, string.Length, string.Length. O qualcosa di simile che ha senso nel contesto StringBuilder.

+0

Sembra (dalla risposta di Damien, per la quale ha usato Reflector) il tuo primo "probabilmente" era giusto, e il tuo secondo era vicino (in realtà la potenza successiva di 16, al contrario di solo 'stringa.Lunghezza'). –

+0

... e con "la prossima potenza di 16", intendo "16 volte la potenza successiva di 2". Non penso che dopo il 16 andrà dritto a 256 e poi a 4096 (sono stupido). –

1

Il costruttore che alla fine viene chiamato è:

// "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) 

(Questo non è altro che le altre risposte non forniscono, ed è proprio da riflettore)
Se la capacità è inferiore alla lunghezza della stringa, che è in questo caso:

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

in Mono, costruttore StringBuilder(string val) alloca la capacità di int.MaxValue finché non si verifica un accodamento.

La vera risposta sta nel metodo che finisce per essere chiamato internamente nel CLR, in cui la lunghezza è la capacità:

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

Non riesco a trovare la fonte per questo nel SSCLI tuttavia la versione Mono (\ mono \ metadati \ object.c) lo fa in questo modo:

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

... 
} 

Qual è la dimensione in byte di un oggetto MonoString, più la lunghezza volte 2.

+0

Da dove proviene questa informazione? Stai usando Windows, Mono o ...? Sembra che le tue scoperte riguardo alla capacità iniziale di 'StringBuilder' differiscano da quelle di Damien (e mia). –

+0

@Dan - un piccolo errore con 0x10 :) –

+0

Il codice che hai fornito è utile, ma è in conflitto con quello che hai detto! "Il costruttore usa la lunghezza della stringa come capacità" - questo non è vero; che 'while' loop raddoppia' capacità' fino a 'capacità> = lunghezza'; quindi sarà il suo valore di partenza (che sembra essere 16) volte una potenza di 2. –