Question

Ma question est la suivante: est la concaténation de chaîne en C # en sécurité? Si la concaténation de chaîne conduit à des erreurs inattendues, et le remplacement de cette concaténation de chaîne à l'aide StringBuilder provoque ces erreurs à disparaître, ce qui pourrait indiquer que?

Contexte: Je développe une petite ligne de commande C # application. Il faut des arguments de ligne de commande, effectue une requête SQL peu compliquée, et génère environ 1300 lignes de données dans un fichier au format XML.

Mon programme initial serait toujours bien fonctionner en mode de débogage. Cependant, en mode de libération, il obtiendrait environ le 750e résultat SQL, puis mourir avec une erreur. L'erreur était qu'une certaine colonne de données ne peut pas être lu, même par la méthode Read () de l'objet SqlDataReader venait de rentrer vrai.

Ce problème a été résolu en utilisant StringBuilder pour toutes les opérations dans le code, là où auparavant il y avait eu « chaîne1 + chaîne2 ». Je ne parle pas de concaténation de chaîne dans la boucle de requête SQL, où StringBuilder était déjà en cours d'utilisation. Je parle de concaténations simples entre deux ou trois variables de chaîne courte antérieures dans le code.

J'ai eu l'impression que C # était assez intelligent pour gérer la gestion de la mémoire pour ajouter quelques cordes ensemble. Ai-je tort? Ou que cela indique un autre type de problème de code?

Était-ce utile?

La solution

En dehors de ce que vous faites est probablement mieux fait avec les API XML au lieu de chaînes ou StringBuilder je doute que l'erreur que vous voyez est due à la concaténation de chaîne. Peut-être passer à StringBuilder juste masqué l'erreur ou est allé au-dessus avec grâce, mais je doute à l'aide des cordes est vraiment la cause.

Autres conseils

Pour répondre à votre question: Chaîne contatenation en C # (et .NET en général) « sûr », mais le faire dans une boucle serrée que vous décrivez est susceptible de provoquer une pression sévère de la mémoire et mettre une pression sur le collecteur de déchets.

Je hasarder une hypothèse que les erreurs dont vous parlez étaient liés à l'épuisement des ressources de quelque sorte, mais il serait utile que vous fournir plus de détails - par exemple, avez-vous reçu une exception? Est-ce que l'application fin anormale?

Contexte: chaînes .NET sont immuables, donc quand vous faites une concaténation comme ceci:

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

est à peu près équivalent à ce qui suit:

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;

Le but de cet exemple est de souligner que chaque fois les résultats de la boucle dans l'attribution d'une nouvelle chaîne temporaire.

Étant donné que les chaînes sont immuables, le moteur d'exécution n'a pas d'autres options, mais d'allouer une nouvelle chaîne à chaque fois que vous ajoutez une autre chaîne à la fin de votre résultat.

Bien que la chaîne de result est constamment mis à jour pour pointer vers le dernier et le plus grand résultat intermédiaire, vous produisez beaucoup de ces chaîne temporaire non nommé qui deviennent admissibles à la collecte des ordures presque immédiatement.

A la fin de cette concaténation vous aurez les chaînes suivantes stockées dans la mémoire (en supposant, pour simplifier, que le garbage collector n'a pas encore exécuté).

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";
// ...

Bien que toutes ces variables temporaires implicites sont admissibles à la collecte des ordures presque immédiatement, ils doivent encore être attribués. Lorsque vous effectuez concaténation dans une boucle serrée cela va mettre beaucoup de pression sur le collecteur des ordures et, si rien d'autre, fera votre code d'exécution très lentement. Je l'ai vu l'impact sur les performances de cette première main, et il devient vraiment dramatique que votre chaîne concaténée devient plus grande.

L'approche recommandée est d'utiliser toujours un StringBuilder si vous faites plus de quelques concaténations de chaînes. StringBuilder utilise un tampon Mutable pour réduire le nombre d'allocations qui sont nécessaires à la construction de votre chaîne.

concaténation chaîne est sûr que plus de mémoire que l'aide d'un StringBuilder si contatenating un grand nombre de chaînes dans une boucle. Et dans les cas extrêmes, vous pourriez manquer de mémoire.

Il est presque certainement un bug dans votre code.

Peut-être que vous contatenating un très grand nombre de chaînes. Ou peut-être quelque chose d'autre complètement différent.

Je vais revenir au débogage sans idées préconçues de la cause - si vous avez toujours des problèmes essayer de réduire au minimum nécessaire pour repro le problème et le code postal

.

Combien de temps faudrait-il la version concaténation vs la version constructeur de chaîne? Il est possible que votre connexion au DB est fermé. Si vous faites beaucoup de concaténation, je vais w / StringBuilder comme il est un peu plus efficace.

L'une des causes est peut-être que les chaînes sont immuables en .Net donc quand vous faites une opération sur une telle que concaténation vous créez en fait une nouvelle chaîne.

Une autre cause possible est que la longueur de chaîne est un entier de sorte que la longueur maximale possible est Int32.MaxValue ou 2147483647.

Dans les deux cas, un StringBuilder est mieux que « chaîne1 + chaîne2 » pour ce type d'opération. Bien que, en utilisant les fonctionnalités XML intégrées serait encore mieux.

string.Concat(string[]) est de loin le meilleur moyen de concaténer des chaînes. Il tue litterly StringBuilder en performance lorsqu'il est utilisé dans les boucles, surtout si vous créez le StringBuilder à chaque itération. Il y a des tas de références si vous Google « c # format de chaîne vs stringbuilder » ou quelque chose comme ça. http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx vous donne un ideer sur les temps. Ici string.join remporte le test de concaténation mais je belive cela est parce que le string.Concat(string, string) est utilisé au lieu de la version surchargée qui prend un tableau. Si vous regardez le code MSIL qui est généré par les différentes méthodes que vous verrez ce qui se passe sous le capot.

Voici mon coup dans l'obscurité ...

Cordes dans .NET (non stringbuilders) entrent dans la chaîne Intern Pool. Ceci est essentiellement une zone gérée par le CLR pour partager des chaînes pour améliorer les performances. Il doit y avoir une limite ici, même si je ne sais pas ce que cette limite est. J'imagine tout l'enchaînement que vous faites est de frapper le plafond de la piscine interne de chaînes. Donc, dit SQL oui j'ai une valeur pour vous, mais il ne peut pas le mettre partout et vous obtenez une exception.

Un test rapide et facile serait de nGen votre assemblée et voir si vous obtenez toujours l'erreur. Après nGen'ing, votre application n'utilisera la piscine.

Si cela échoue, je contacter Microsoft pour essayer d'obtenir quelques détails difficiles. Je pense que mon idée semble plausible, mais je ne sais pas pourquoi cela fonctionne en mode débogage. Peut-être que dans les chaînes de mode de débogage ne sont pas interné. Je suis pas expert.

Lors de compoundage des chaînes de caractères que j'utilise toujours StringBuilder. Il est conçu pour elle et est plus efficace que la simple utilisation « chaîne1 + chaîne2 ».

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top