2009-02-02 8 views
6

StringBuilder a la réputation d'être un outil de manipulation de chaînes plus rapide que la simple concaténation de chaînes. Que ce soit vrai ou non, je me pose des questions sur les résultats des opérations de StringBuilder et les chaînes qu'ils produisent. Une petite balade dans Reflector montre que StringBuilder.ToString() ne renvoie pas toujours une copie, parfois il semble renvoyer une instance de la chaîne interne. Il semble également utiliser certaines fonctions internes pour manipuler les chaînes internes.Les chaînes StringBuilder sont-elles immuables?

Alors qu'est-ce que je reçois si je fais cela?

string s = "Yo Ho Ho"; 
StringBuilder sb = new StringBuilder(s); 
string newString = sb.ToString(); 
sb.Append(" and a bottle of rum."); 
string newNewString = sb.ToString(); 

sont-nouvelleChaine et newNewString différentes instances de chaîne ou le même? J'ai essayé de comprendre cela par réflecteur, et je ne comprends tout simplement pas tout.

Que diriez-vous de ce code?

StringBuilder sb = new StringBuilder("Foo\n"); 
StringReader sr = new StringReader(sb.ToString()); 
string s = sr.ReadLine(); 
sb.Append("Bar\n"); 
s = sr.ReadLine(); 

La dernière instruction renverra-t-elle la valeur null ou "Bar"? Et s'il renvoie l'un ou l'autre, ce comportement est-il défini ou indéfini? En d'autres termes, puis-je m'en remettre?

La documentation est remarquablement laconique sur ce sujet, et je suis réticent à me fier au comportement observé plutôt qu'aux spécifications.

+0

Veuillez noter que l'implémentation de StringBuilder a changé depuis que cette question a été posée et répondue. – mayu

Répondre

10

En dehors de mscorlib, toute instance d'un System.String est immuable, point. StringBuilder effectue une manipulation intéressante des chaînes en interne, mais à la fin de la journée, il ne vous renvoie pas de chaîne, puis la mute ensuite d'une manière visible pour votre code. Pour savoir si les appels suivants à StringBuilder.ToString() renvoient la même instance d'une chaîne ou d'une chaîne différente avec la même valeur, cela dépend de l'implémentation et vous ne devez pas vous fier à ce comportement.

+0

Oui, l'expérimentation a montré que c'est vrai, mais la spéléologie dans les internes avec Reflector n'a pas montré pourquoi. Il semble retourner une référence à la chaîne interne à chaque appel, d'où ma confusion quant à savoir si la chaîne pourrait muter. –

+0

@Mystere, L'implémentation de StringBuilder est un peu intimidante au début. Jusqu'à ce que je lisais votre question et que je commençais à explorer, je ne savais pas qu'ils faisaient du cache au niveau du thread. Je prévois de regarder plus tard ce soir (ou demain). Mais vous pouvez croire que la chaîne résultante est immuable – JaredPar

4

newString et newNewString sont des instances de chaîne différentes.

Bien que ToString() renvoie la chaîne en cours, il efface sa variable de thread actuelle. Cela signifie que la prochaine fois que vous ajoutez, il faudra une copie de la chaîne en cours avant de l'ajouter.

Je ne suis pas entièrement sûr de ce que vous obtenez à votre deuxième question, mais s sera nulle: si les caractères finaux dans un fichier sont le caractère de terminaison de ligne (s) pour la ligne précédente, la ligne est pas réputé avoir une ligne vide entre ces caractères et la fin du fichier. La chaîne qui a été lue précédemment ne fait pas de différence.

+0

Ahh .. vous m'avez expliqué le mystère. Effacer la variable de fil est ce qui provoque la copie sur append, simple mais non-évident. Ma deuxième question était une variation sur la question de mutabilité, relative à une référence stockée dans StringReader. –

2

Le but de cette classe est de rendre la chaîne mutable, donc c'est effectivement le cas. Je crois (mais je ne suis pas sûr) que ça retournera la même chaîne que si rien d'autre n'avait été fait avec cet objet. Donc, après

String s_old = "Foo"; 
StringBuilder sb = new StringBuilder(s_old); 
String s_new = sb.ToString(); 

s_old serait le même que s_new mais ce ne sera pas dans un autre cas.

Je devrais noter, que pour le compilateur Java convertir automatiquement plusieurs ajouts de chaîne en opérations avec StringBuilder (ou StringBuffer qui est similaire mais encore plus rapide) classe et je serais vraiment surpris.Le compilateur NET ne fait pas cette conversion aussi.

+0

Le compilateur C# n'utilise pas StringBuilder pour les concaténations de chaînes - il utilise String.Concat. Cela signifie que la longueur finale est connue avant toute concaténation. –

3

sont-newString et newNewString différentes instances string ou même? J'ai essayé de comprendre cela par réflecteur, et je ne comprends pas tout à fait.

Ils sont différents cas string: newString est "Yo Ho Ho" et newNewString est "Yo Ho Ho and a bottle of rum.". strings sont immuables et lorsque vous appelez StringBuilder.ToString() la méthode renvoie un string immuable qui représente l'état actuel.

Est-ce que la dernière déclaration de retour null ou "Bar"? Et s'il renvoie un ou plusieurs autre, est-ce que ce comportement est défini ou non ? En d'autres termes, puis-je me fier à ?

Il renverra null. Le StringReader fonctionne sur le string immuable que vous lui avez passé au constructeur, donc il n'est pas affecté par ce que vous faites au StringBuilder.

Questions connexes