J'ai un petit morceau de code qui analyse une valeur d'index pour déterminer une entrée de cellule dans Excel. Cela me fait réfléchir ...
Quelle est la différence entre
xlsSheet.Write("C" + rowIndex.ToString(), null, title);
et
xlsSheet.Write(string.Format("C{0}", rowIndex), null, title);
Est-ce que l'un est meilleur que l'autre? Et pourquoi?
Réponses:
Avant C # 6
Pour être honnête, je pense que la première version est plus simple - même si je la simplifierais comme suit:
Je soupçonne que d'autres réponses peuvent parler de l'impact sur les performances, mais pour être honnête, ce sera minime, voire présent - et cette version de concaténation n'a pas besoin d'analyser la chaîne de format.
Les chaînes de format sont idéales pour la localisation, etc., mais dans un cas comme celui-ci, la concaténation est plus simple et fonctionne tout aussi bien.
Avec C # 6
L'interpolation de chaîne simplifie la lecture de beaucoup de choses en C # 6. Dans ce cas, votre deuxième code devient:
qui est probablement la meilleure option, l'OMI.
la source
xlsSheet.Write($"C{rowIndex}", null, title);
Ma préférence initiale (venant d'un arrière-plan C ++) était pour String.Format. J'ai laissé tomber ceci plus tard pour les raisons suivantes:
- La concaténation de chaînes autorise les valeurs nulles,String.Format
non. L'écriture "s1 + null + s2
" ne casse pas, elle traite simplement la valeur nulle comme String.Empty. Eh bien, cela peut dépendre de votre scénario spécifique - il y a des cas où vous souhaitez une erreur au lieu d'ignorer silencieusement un FirstName nul. Cependant, même dans cette situation, je préfère personnellement vérifier moi-même les nulls et lancer des erreurs spécifiques au lieu de l'exception ArgumentNullException standard que j'obtiens de String.Format.L'idée est que le compilateur .NET est suffisamment intelligent pour convertir ce morceau de code:
pour ça:
Ce qui se passe sous le capot de String.Concat est facile à deviner (utilisez Reflector). Les objets du tableau sont convertis en leur chaîne via ToString (). Ensuite, la longueur totale est calculée et une seule chaîne est allouée (avec la longueur totale). Enfin, chaque chaîne est copiée dans la chaîne résultante via wstrcpy dans un morceau de code non sécurisé.
Raisons
String.Concat
est beaucoup plus rapide? Eh bien, nous pouvons tous voir ce quiString.Format
se passe - vous serez surpris de la quantité de code nécessaire pour traiter la chaîne de format. En plus de cela (j'ai vu des commentaires concernant la consommation de mémoire),String.Format
utilise un StringBuilder en interne. Voici comment:StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
Donc, pour chaque argument passé, il réserve 8 caractères. Si l'argument est une valeur à un chiffre, alors tant pis, nous avons un espace perdu. Si l'argument est un objet personnalisé renvoyant du texte long
ToString()
, une réallocation peut même être nécessaire (dans le pire des cas, bien sûr).Par rapport à cela, la concaténation ne gaspille que l'espace du tableau d'objets (pas trop, en tenant compte que c'est un tableau de références). Il n'y a pas d'analyse pour les spécificateurs de format et aucun StringBuilder intermédiaire. La surcharge de boxe / déballage est présente dans les deux méthodes.
La seule raison pour laquelle j'opterais pour String.Format est lorsque la localisation est impliquée. Le fait d'insérer des chaînes de format dans les ressources vous permet de prendre en charge différentes langues sans modifier le code (pensez aux scénarios où les valeurs formatées changent d'ordre en fonction de la langue, c'est-à-dire que "après {0} heures et {1} minutes" peut être assez différent en japonais: ).
Pour résumer mon premier (et assez long) post:
ToString()
appelToString()
appels vous-même pour éviter la boxe (je suis quelque peu biaisé pour la lisibilité) - comme la première option de votre questionString.Format()
a un bord.la source
string.Format
est «sûr» lors de l'utilisation de ReSharper; c'est-à-dire qu'il est aussi sûr que tout autre code qui peut être utilisé [incorrectement]. 2)string.Format
ne permet un « sûr »null
:string.Format("A{0}B", (string)null)
résultats dans « AB ». 3) Je me soucie rarement de ce niveau de performance (et à cette fin, c'est un jour rare où je me retireStringBuilder
) ...string s = "This " + MyMethod(arg) + " is a test";
est compilé en unString.Concat()
appel en mode Release.Je pense que la première option est plus lisible et que cela devrait être votre principale préoccupation.
string.Format utilise un StringBuilder sous le capot (vérifiez avec le réflecteur ) donc il n'aura aucun avantage en termes de performances à moins que vous ne fassiez une quantité significative de concaténation. Ce sera plus lent pour votre scénario, mais la réalité est que cette décision d'optimisation des micro performances est inappropriée la plupart du temps et vous devriez vraiment vous concentrer sur la lisibilité de votre code à moins que vous ne soyez dans une boucle.
Dans tous les cas, écrivez d'abord pour la lisibilité, puis utilisez un profileur de performances pour identifier vos hotspots si vous pensez vraiment avoir des problèmes de performances.
la source
Pour un cas simple où il s'agit d'une simple concaténation unique, je pense que cela ne vaut pas la complexité de
string.Format
(et je n'ai pas testé, mais je soupçonne que pour un cas simple comme celui-ci, celastring.Format
pourrait être légèrement plus lent, avec l'analyse de la chaîne de format et tout). Comme Jon Skeet, je préfère ne pas appeler explicitement.ToString()
, car cela sera fait implicitement par lastring.Concat(string, object)
surcharge, et je pense que le code est plus propre et plus facile à lire sans lui.Mais pour plus de quelques concaténations (combien est subjectif), je préfère définitivement
string.Format
. À un certain moment, je pense que la lisibilité et les performances souffrent inutilement de la concaténation.S'il y a beaucoup de paramètres dans la chaîne de format (encore une fois, "beaucoup" est subjectif), je préfère généralement inclure des indices commentés sur les arguments de remplacement, de peur de perdre la trace de quelle valeur va à quel paramètre. Un exemple artificiel:
Mettre à jour
Il me semble que l'exemple que j'ai donné est un peu déroutant, car il semble que j'ai utilisé à la fois la concaténation et
string.Format
ici. Et oui, logiquement et lexiquement, c'est ce que j'ai fait. Mais les concaténations seront toutes optimisées par le compilateur 1 , car ce sont toutes des chaînes littérales. Donc, au moment de l'exécution, il y aura une seule chaîne. Je suppose donc que je devrais dire que je préfère éviter de nombreuses concaténations au moment de l'exécution .Bien sûr, la plupart de ce sujet est désormais obsolète, à moins que vous ne soyez toujours bloqué en utilisant C # 5 ou une version antérieure. Maintenant, nous avons des chaînes interpolées , qui, pour la lisibilité, sont bien supérieures à
string.Format
, dans presque tous les cas. Ces jours-ci, à moins que je ne concatène une valeur directement au début ou à la fin d'une chaîne littérale, j'utilise presque toujours l'interpolation de chaîne. Aujourd'hui, j'écrirais mon exemple précédent comme ceci:Vous perdez ainsi la concaténation au moment de la compilation. Chaque chaîne interpolée est transformée en un appel
string.Format
par le compilateur et leurs résultats sont concaténés au moment de l'exécution. Cela signifie qu'il s'agit d'un sacrifice des performances d'exécution pour la lisibilité. La plupart du temps, c'est un sacrifice qui en vaut la peine, car la pénalité d'exécution est négligeable. Dans le code critique de performances, cependant, vous devrez peut-être profiler différentes solutions.1 Vous pouvez voir ceci dans la spécification C # :
Vous pouvez également le vérifier avec un petit code:
la source
String.Format()
Si votre chaîne était plus complexe avec de nombreuses variables concaténées, je choisirais la chaîne.Format (). Mais pour la taille de la chaîne et le nombre de variables concaténées dans votre cas, j'irais avec votre première version, c'est plus spartiate .
la source
J'ai jeté un coup d'œil à String.Format (en utilisant Reflector) et il crée en fait un StringBuilder puis appelle AppendFormat dessus. Il est donc plus rapide que concat pour plusieurs brassages. Le plus rapide (je crois) serait de créer un StringBuilder et de faire les appels à Append manuellement. Bien sûr, le nombre de "plusieurs" est à deviner. J'utiliserais + (en fait et parce que je suis principalement un programmeur VB) pour quelque chose d'aussi simple que votre exemple. Au fur et à mesure que cela devient plus complexe, j'utilise String.Format. S'il y a BEAUCOUP de variables, j'opterais pour un StringBuilder et un Append, par exemple, nous avons du code qui construit du code, j'utilise une ligne de code réel pour générer une ligne de code généré.
Il semble y avoir des spéculations sur le nombre de chaînes créées pour chacune de ces opérations, prenons donc quelques exemples simples.
"C" est déjà une chaîne.
rowIndex.ToString () crée une autre chaîne. (@manohard - aucun encadrement de rowIndex ne se produira)
Ensuite, nous obtenons la chaîne finale.
Si nous prenons l'exemple de
puis nous avons "C {0}" comme chaîne
rowIndex est encadrée pour être transmise à la fonction
Un nouveau stringbuilder est créé
AppendFormat est appelé sur le string builder - je ne connais pas les détails de la façon dont AppendFormat fonctionne mais supposons que c'est ultra efficace, il va encore falloir convertir le rowIndex encadré en une chaîne.
Ensuite, convertissez le constructeur de chaînes en une nouvelle chaîne.
Je sais que StringBuilders tente d'empêcher des copies de mémoire inutiles, mais le String.Format se termine toujours par une surcharge supplémentaire par rapport à la concaténation simple.
Si nous prenons maintenant un exemple avec quelques chaînes de plus
nous avons 6 chaînes pour commencer, qui seront les mêmes dans tous les cas.
En utilisant la concaténation, nous avons également 4 chaînes intermédiaires plus le résultat final. Ce sont ces résultats intermédiaires qui sont éliminés en utilisant String, Format (ou un StringBuilder).
N'oubliez pas que pour créer chaque chaîne intermédiaire, la précédente doit être copiée dans un nouvel emplacement mémoire, ce n'est pas seulement l'allocation mémoire qui est potentiellement lente.
la source
J'aime String.Format car il peut rendre votre texte formaté beaucoup plus facile à suivre et à lire que la concaténation en ligne, il est également beaucoup plus flexible vous permettant de formater vos paramètres, mais pour de courtes utilisations comme la vôtre, je ne vois aucun problème à concaténer.
Pour les concaténations à l'intérieur de boucles ou dans de grandes chaînes, vous devez toujours essayer d'utiliser la classe StringBuilder.
la source
Cet exemple est probablement trop trivial pour remarquer une différence. En fait, je pense que dans la plupart des cas, le compilateur peut optimiser toute différence.
Cependant, si je devais deviner, je donnerais
string.Format()
un avantage pour des scénarios plus compliqués. Mais c'est plus un sentiment instinctif qu'il est susceptible de faire un meilleur travail en utilisant un tampon au lieu de produire plusieurs chaînes immuables, et non sur la base de données réelles.la source
Je suis d'accord avec beaucoup de points ci-dessus, un autre point qui, je crois, devrait être mentionné est la maintenabilité du code. string.Format permet un changement de code plus facile.
ie j'ai un message
"The user is not authorized for location " + location
ou"The User is not authorized for location {0}"
si jamais je voulais changer le message pour dire:
location + " does not allow this User Access"
ou"{0} does not allow this User Access"
avec string.Format tout ce que j'ai à faire est de changer la chaîne. pour la concaténation, je dois modifier ce message
s'il est utilisé à plusieurs endroits, il peut gagner du temps.
la source
J'avais l'impression que string.format était plus rapide, il semble être 3 fois plus lent dans ce test
string.format a pris 4,6 secondes et lors de l'utilisation de '+', il a fallu 1,6 secondes.
la source
"1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" + "10"
comme une chaîne littérale, donc la ligne devient effectivement"12345678910" + i
ce qui est plus rapide que la précédentestring.Format(...)
string.Format est probablement un meilleur choix lorsque le modèle de format ("C {0}") est stocké dans un fichier de configuration (tel que Web.config / App.config)
la source
J'ai fait un peu de profilage de diverses méthodes de chaîne, y compris string.Format, StringBuilder et la concaténation de chaînes. La concaténation de chaînes surpassait presque toujours les autres méthodes de création de chaînes. Donc, si la performance est la clé, c'est mieux. Cependant, si les performances ne sont pas critiques, je trouve personnellement que string.Format est plus facile à suivre dans le code. (Mais c'est une raison subjective) StringBuilder est probablement le plus efficace en ce qui concerne l'utilisation de la mémoire.
la source
Je préfère String.Format en ce qui concerne les performances
la source
La concaténation de chaînes prend plus de mémoire que String.Format. La meilleure façon de concaténer des chaînes consiste donc à utiliser String.Format ou System.Text.StringBuilder Object.
Prenons le premier cas: "C" + rowIndex.ToString () Supposons que rowIndex est un type de valeur donc la méthode ToString () doit Box pour convertir la valeur en String, puis CLR crée de la mémoire pour la nouvelle chaîne avec les deux valeurs incluses.
Où en tant que string.Format attend le paramètre d'objet et prend dans rowIndex comme un objet et le convertit en chaîne en interne, il y aura de la boxe, mais c'est intrinsèque et cela ne prendra pas autant de mémoire que dans le premier cas.
Pour les cordes courtes, cela n'a pas d'importance, je suppose ...
la source