Domanda

La mia domanda è questa: è la concatenazione di stringhe in C # è sicuro? Se concatenazione di stringhe porta a errori imprevisti, e sostituisce quello concatenazione di stringhe utilizzando StringBuilder fa sì che quegli errori a scomparire, ciò che potrebbe indicare che?

Sfondo: sto sviluppando una piccola linea di comando applicazione C #. Prende gli argomenti della riga di comando, esegue una query SQL un po 'complicato, ed emette circa 1300 righe di dati in un file in formato XML.

Il mio programma iniziale sarebbe sempre funzionare bene in modalità debug. Tuttavia, nella modalità di rilascio si otterrebbe a circa il risultato SQL 750 °, e poi morire con un errore. L'errore è stato che una certa colonna di dati non può essere letta, anche attraverso il metodo Read () dell'oggetto SqlDataReader era appena tornato vero.

Il problema è stato risolto utilizzando StringBuilder per tutte le operazioni nel codice, dove in precedenza c'era stata "stringa1 + stringa2". Non sto parlando di concatenazione di stringhe all'interno del ciclo query SQL, dove StringBuilder era già in uso. Sto parlando di semplici concatenazioni tra due o tre brevi variabili stringa precedenti nel codice.

Ho avuto l'impressione che C # è stato abbastanza intelligente per gestire la gestione della memoria per l'aggiunta di un paio di stringhe. Ho sbagliato? O questo indica qualche altro tipo di problema di codice?

È stato utile?

Soluzione

A parte quello che stai facendo è probabilmente la cosa migliore fatto con le API XML, invece di stringhe o StringBuilder dubito che l'errore che si vede è dovuto alla concatenazione di stringhe. Forse il passaggio a StringBuilder appena mascherato l'errore o è andato su di esso con grazia, ma dubito utilizzando stringhe in realtà è stata la causa.

Altri suggerimenti

Per rispondere alla tua domanda: String contatenation in C # (e .NET in generale) è "sicuro", ma farlo in un loop stretto come lei rischia di causare gravi pressione della memoria e mettere a dura prova il garbage collector.

Vorrei azzardare un'ipotesi che gli errori di cui parli sono state correlate a esaurimento risorse di qualche tipo, ma sarebbe utile se potesse fornire maggiori dettagli - per esempio, avete ricevuto un'eccezione? Ha fatto l'applicazione terminare in modo anomalo?

Sfondo: stringhe .NET sono immutabili, in modo che quando si fa una concatenazione in questo modo:

var stringList = new List<string> {"aaa", "bbb", "ccc", "ddd", //... };
string result = String.Empty;
foreach (var s in stringList)
{
    result = result + s;
}

Questo è più o meno equivalente al seguente:

string result = "";
result = "aaa"
string temp1 = result + "bbb";
result = temp1;
string temp2 = temp1 + "ccc";
result = temp2;
string temp3 = temp2 + "ddd";
result = temp3;
// ...
result = tempN + x;

Lo scopo di questo esempio è quello di sottolineare che ogni volta i risultati di loop nella ripartizione di una nuova stringa temporanea.

Dal momento che le stringhe sono immutabili, il runtime non ha opzioni alternative, ma per allocare una nuova stringa ogni volta che si aggiunge un'altra stringa alla fine del vostro risultato.

Anche se la stringa result è costantemente aggiornato per puntare la versione più recente risultato intermedio, si stanno producendo un sacco di questi stringa temporanea senza nome che diventano per la garbage collection quasi immediatamente.

Al termine di questa concatenazione si avrà le seguenti stringhe memorizzati nella memoria (assumendo, per semplicità, che il garbage collector non ha ancora eseguito).

string a = "aaa";
string b = "bbb";
string c = "ccc";
// ...
string temp1 = "aaabbb";
string temp2 = "aaabbbccc";
string temp3 = "aaabbbcccddd";
string temp4 = "aaabbbcccdddeee";
string temp5 = "aaabbbcccdddeeefff";
string temp6 = "aaabbbcccdddeeefffggg";
// ...

Anche se tutte queste variabili temporanee implicite sono per la garbage collection quasi subito, hanno ancora da assegnare. Quando si esegue la concatenazione in un loop stretto questo sta per mettere un sacco di tensione sulla garbage collector e, se non altro, renderà il vostro codice di funzionare molto lentamente. Ho visto l'impatto sulle prestazioni di questa prima mano, e diventa veramente drammatica come stringa concatenata diventa più grande.

L'approccio consigliato è di usare sempre un StringBuilder se si sta facendo più di un paio di concatenazioni di stringhe. StringBuilder utilizza un buffer variabile per ridurre il numero di allocazioni che sono necessari a costruire la stringa.

La concatenazione di stringhe è sicuro anche se più intensivo di memoria rispetto all'utilizzo di uno StringBuilder se contatenating un gran numero di stringhe in un ciclo. E in casi estremi si potrebbe essere a corto di memoria.

E 'quasi certamente un bug nel codice.

Forse stai contatenating un gran numero di stringhe. O forse è qualcosa di completamente diverso.

Mi piacerebbe tornare per il debug senza preconcetti la causa principale - se hai ancora problemi di cercare di ridurlo al minimo necessario a Repro il codice problema e post

.

Quanto tempo ci vorrebbe la versione di concatenazione vs la versione stringa builder? E 'possibile che la connessione al DB viene chiuso. Se stai facendo un sacco di concatenamento, vorrei andare w / StringBuilder in quanto è un po 'più efficiente.

Una causa può essere che le stringhe sono immutabili in .Net in modo che quando si fa un'operazione su uno come concatenazione in realtà si sta creando una nuova stringa.

Un'altra causa possibile che la lunghezza stringa è un int così la lunghezza massima possibile è Int32.MaxValue o 2.147.483.647.

In entrambi i casi uno StringBuilder è meglio di "string1 string2 +" per questo tipo di operazione. Anche se, utilizzando le funzionalità XML integrate sarebbe ancora meglio.

string.Concat(string[]) è di gran lunga il modo più veloce per concatenare le stringhe. Uccide litterly StringBuilder in termini di prestazioni quando viene utilizzato in loop, soprattutto se si crea il StringBuilder in ogni iterazione. Ci sono un sacco di riferimenti se google "c # formato stringa vs StringBuilder" o qualcosa di simile. http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx ti dà un'ideer sui tempi. Qui string.join vince il test di concatenazione ma belive questo è perché il string.Concat(string, string) è usato al posto della versione di overload che accetta un array. Se si dà un'occhiata al codice MSIL che viene generato dai diversi metodi vedrete cosa succede sotto il cofano.

Ecco il mio salto nel buio ...

Le stringhe in .NET (non stringbuilders) vanno nella stringa Intern Pool. Questo è fondamentalmente un settore gestito dal CLR di condividere le stringhe per migliorare le prestazioni. Ci deve essere un limite qui, anche se non ho idea di che cosa quel limite è. Immagino che tutto il concatenamento che si sta facendo sta colpendo il soffitto della piscina stringa di stagista. Quindi SQL dice sì ho un valore per te, ma non può mettere da nessuna parte in modo da ottenere un'eccezione.

Un test rapido e semplice sarebbe quella di Ngen vostra assemblea e vedere se è ancora ottenere l'errore. Dopo nGen'ing, è l'applicazione non sarà più l'uso della piscina.

Se non funziona, mi piacerebbe contattare Microsoft per cercare di ottenere alcuni dettagli duri. Credo che la mia idea sembra plausibile, ma non ho idea perché funziona in modalità debug. Forse in stringhe modalità di debug non sono internati. Sono anche un esperto.

Quando compounding stringhe che uso sempre StringBuilder. E 'progettato per esso ed è più efficiente che semplicemente utilizzando "stringa1 + stringa2".

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top