Question

Disons que vous voulez de sortie ou la concaténation de chaînes de caractères.Lequel de ces styles préférez-vous?

  • var p = new { FirstName = "Bill", LastName = "Gates" };

  • Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

  • Console.WriteLine(p.FirstName + " " + p.LastName);

Avez-vous plutôt d'utiliser le format ou avez-vous tout simplement la concaténation de chaînes de caractères?Quel est votre favori?Est l'un de ces mal à vos yeux?

Avez-vous des arguments rationnels pour utiliser l'un et pas l'autre?

J'irais pour le second.

Était-ce utile?

La solution

Essayez ce code.

C'est une version légèrement modifiée de votre code.
1.J'ai supprimé de la Console.WriteLine que c'est probablement quelques ordres de grandeur plus lent que ce que je suis en train de mesurer.
2.Je commence le Chronomètre avant la boucle et de l'arrêter tout de suite après, de cette façon, je ne suis pas perdant en précision si la fonction prend pour exemple 26.4 tiques à exécuter.
3.La façon dont vous avez divisé le résultat par quelques itérations a été mauvais.Voir ce qui se passe si vous avez 1000 millisecondes et 100 millisecondes.Dans les deux cas, vous obtiendrez 0 ms après le divisant par 1000000.

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();


Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);

Ce sont mes résultats:

1000000 x result = string.Format("{0} {1}", p.Prénom, p.LastName);a:618ms - 2213706 tiques
1000000 x résultat = (p.Prenom + "" + p.LastName);a:166ms - 595610 tiques

Autres conseils

Je suis étonné de voir que tant de gens immédiatement envie de trouver le code qui s'exécute de la manière la plus rapide. Si UN MILLION d'itérations ENCORE moins d'une seconde, est-ce que ce sera en AUCUNE FAÇON perceptible pour l'utilisateur final?Pas très probable.

L'optimisation prématurée = ÉCHEC.

J'irais avec le String.Format option, uniquement parce qu'il fait le plus de sens à partir d'un point de vue architectural.Je ne m'inquiète pas au sujet de la performance jusqu'à ce qu'elle devient un problème (et si elle le faisait, je me pose:Ai-je besoin de concaténer un million de noms à la fois?Sûrement ils ne rentrent pas tous sur l'écran...)

Considérez si votre client désire modifier de sorte qu'ils peuvent configurer l'affichage "Firstname Lastname" ou "Lastname, Firstname." Avec l'option de Format, c'est facile, il vous suffit de changer la chaîne de format.Avec la méthode concat, vous aurez besoin de code supplémentaire.Assurez-vous que ne pas sembler une grosse affaire dans cet exemple particulier, mais d'extrapoler.

Oh - après la lecture de l'une des autres réponses, j'ai essayé d'inverser l'ordre des opérations, d'effectuer la concaténation d'abord, puis de la Chaîne.Format de...

Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 8ms - 30488 ticks
Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 0ms - 182 ticks

Donc, l'ordre des opérations fait une ÉNORME différence, ou plutôt la première opération est TOUJOURS beaucoup plus lent.

Voici les résultats d'une course où les opérations sont terminées plus d'une fois.J'ai essayé de changer les commandes, mais les choses suivent en général les mêmes règles, une fois que le premier résultat est ignoré:

Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 5ms - 20335 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 156 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 122 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 181 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 122 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 142 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 117 ticks

Comme vous pouvez le voir les passages suivants de la même méthode (j'ai refait le code en 3 méthodes) sont progressivement plus rapide.La manière la plus rapide semble être la Console.WriteLine(String.Concat(...)) de la méthode, suivi par les normal de concaténation, et puis la mise en forme des opérations.

Le délai initial de démarrage est probablement l'initialisation de la Console de Flux, que la pose d'une Console.Writeline("Start!") avant la première opération apporte tous les temps de retour en ligne.

Les chaînes sont immuables, ce qui signifie la même en tout petit morceau de la mémoire est utilisée à plusieurs reprises dans votre code.En ajoutant le même deux chaînes et de la création de la nouvelle chaîne, à maintes reprises et n'a pas d'impact de la mémoire..Net est assez intelligent pour utiliser la même mémoire de référence.Par conséquent, votre code n'a pas vraiment l'essai de la différence entre les deux concat méthodes.

Essayez ceci pour la taille:

Stopwatch s = new Stopwatch();

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0, sbElapsedMilliseconds = 0, sbElapsedTicks = 0;

Random random = new Random(DateTime.Now.Millisecond);

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (random.Next().ToString() + " " + random.Next().ToString());
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();

s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", random.Next().ToString(), random.Next().ToString());
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();

StringBuilder sb = new StringBuilder();
s.Start();
for(var i = 0; i < n; i++){
    sb.Clear();
    sb.Append(random.Next().ToString());
    sb.Append(" ");
    sb.Append(random.Next().ToString());
    result = sb.ToString();
}
s.Stop();
sbElapsedMilliseconds = s.ElapsedMilliseconds;
sbElapsedTicks = s.ElapsedTicks;
s.Reset();

Console.WriteLine(n.ToString() + " x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(\" \"); sb.Append(random.Next().ToString()); result = sb.ToString(); took: " + (sbElapsedMilliseconds) + "ms - " + (sbElapsedTicks) + " ticks");
Console.WriteLine("****************");
Console.WriteLine("Press Enter to Quit");
Console.ReadLine();

Exemple De Sortie:

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 513ms - 1499816 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 393ms - 1150148 ticks
1000000 x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(" "); sb.Append(random.Next().ToString()); result = sb.ToString(); took: 405ms - 1185816 ticks

Pitié les pauvres traducteurs

Si vous savoir votre demande restera en anglais, alors tout va bien, économiser de l'horloge.Cependant, de nombreuses cultures l'habitude de voir Lastname, Firstname, par exemple, des adresses.

Donc de l'utiliser string.Format(), surtout si vous allez jamais votre application à aller n'importe où que l'anglais n'est pas la première langue.

Voici mes résultats de plus de 100 000 itérations:

Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took (avg): 0ms - 689 ticks
Console.WriteLine(p.FirstName + " " + p.LastName); took (avg): 0ms - 683 ticks

Et voici le banc de code:

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

//First print to remove the initial cost
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

int n = 100000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

for (var i = 0; i < n; i++)
{
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();
    cElapsedMilliseconds += s.ElapsedMilliseconds;
    cElapsedTicks += s.ElapsedTicks;
    s.Reset();
    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    fElapsedMilliseconds += s.ElapsedMilliseconds;
    fElapsedTicks += s.ElapsedTicks;
    s.Reset();
}

Console.Clear();

Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took (avg): " + (fElapsedMilliseconds / n) + "ms - " + (fElapsedTicks / n) + " ticks");
Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took (avg): " + (cElapsedMilliseconds / n) + "ms - " + (cElapsedTicks / n) + " ticks");

Donc, je ne sais pas dont la réponse à la marque comme une réponse :)

La concaténation de chaînes est bien dans un scénario simple comme ça - c'est plus compliqué avec quelque chose de plus compliqué que ça, même LastName, FirstName.Avec le format que vous pouvez voir en un coup d'œil ce que la structure finale de la chaîne sera lors de la lecture du code, avec la concaténation, il devient presque impossible pour immédiatement discerner le résultat final (sauf avec un exemple très simple comme celui-ci).

Ce que cela signifie dans le long terme, c'est que lorsque vous revenez à faire un changement à votre format de chaîne de caractères, soit vous avez la possibilité de pop et de faire quelques ajustements à la chaîne de format, ou les rides de vos sourcils et de commencer à se déplacer toutes sortes d'accesseurs de propriété mélangés avec du texte, qui est plus susceptibles de présenter des problèmes.

Si vous êtes en utilisant .NET 3.5, vous pouvez utiliser une méthode d'extension comme celui-ci et d'obtenir un facile coule, au pied levé, la syntaxe ressemble à ceci:

string str = "{0} {1} is my friend. {3}, {2} is my boss.".FormatWith(prop1,prop2,prop3,prop4);

Enfin, en tant que votre demande se développe dans la complexité, vous pouvez décider qu'à sainement maintenir des chaînes dans votre application que vous souhaitez déplacer dans un fichier de ressources pour localiser ou tout simplement une assistance statique.Ce sera BEAUCOUP plus facile à réaliser si vous avez constamment des formats utilisés, et de votre code peut être tout simplement refait à utiliser quelque chose comme

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);

Pour de très simple de manipulation, je voudrais utiliser la concaténation, mais une fois que vous obtenez au-delà de 2 ou 3 éléments de Format devient de plus en plus approprié de l'OMI.

Une autre raison de préférer la Chaîne.Format de est que .NET les chaînes sont immuables et cette façon de faire crée de moins en moins temporaire/intermédiaire des copies.

Alors que je comprends tout à fait le style de la préférence et de la cueillis à la concaténation de ma première réponse, en partie basé sur ma propre préférence, une partie de ma décision était fondée sur l'idée que la concaténation serait plus rapide.Alors, par curiosité, je l'ai testé et les résultats ont été stupéfiants, surtout pour une petite chaîne.

En utilisant le code suivant:

    System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();

    var p = new { FirstName = "Bill", LastName = "Gates" };

    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

    s.Reset();
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();

    Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

J'ai obtenu les résultats suivants:

Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 2ms - 7280 ticks
Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 0ms - 67 ticks

À l'aide de la méthode de formatage est plus de 100 fois plus lent!!La concaténation n'ai pas le même registre que 1ms, c'est pourquoi je sortie de la minuterie tiques ainsi.

Pour la base de concaténation de chaîne, j'utilise généralement le deuxième style - plus facile à lire et simple.Cependant, si je fais une chaîne plus compliqué combinaison j'ai l'habitude d'opter pour la Chaîne.Format.

Chaîne de caractères.Format permet d'économiser sur beaucoup de citations et des avantages...

Console.WriteLine("User {0} accessed {1} on {2}.", user.Name, fileName, timestamp);
vs
Console.WriteLine("User " + user.Name + " accessed " + fileName + " on " + timestamp + ".");

Seulement quelques charicters sauvé, mais je pense que, dans cet exemple, le format le rend beaucoup plus propre.

Un test mieux serait de regarder votre mémoire à l'aide de l'analyseur de performances et le CLR compteurs de mémoire.Ma compréhension est que la seule raison pour laquelle vous souhaitez utiliser des chaînes de caractères.Format au lieu de simplement la concaténation de chaînes de caractères est, depuis les chaînes sont immuables, vous êtes inutilement alourdir le garbage collector avec chaînes temporaires qui doivent être remis en état dans le passage suivant.

StringBuilder et de la Corde.Format, bien que potentiellement plus lent, plus efficace en terme de mémoire.

Ce qui est si mal à propos de la concaténation de chaîne?

En général, je préfère l'ancien, comme en particulier lorsque les cordes sont trop longues, il peut être beaucoup plus facile à lire.

L'autre avantage, c'est que je crois que l'une des performances, que ce dernier se comporte en fait 2 de la chaîne de création de déclarations avant de passer la chaîne finale de la Console.La méthode d'écriture.Chaîne de caractères.Format utilise un StringBuilder sous les couvertures, je crois, de sorte que plusieurs enchaînements sont évités.

Il convient de noter toutefois que, si les paramètres que vous transmettez à la Chaîne.Format (et d'autres méthodes comme la Console.Écriture) sont des types de valeur alors qu'ils seront en boîte avant de passé, qui peut fournir ses propres performances. Blog post à ce sujet ici.

Une semaine à partir de maintenant, Août 19, 2015, cette question sera de sept (7) ans.Il y a maintenant une meilleure façon de le faire. Mieux en termes de maintenabilité que je n'ai pas fait de test de performance comparativement à la concaténation de chaînes (mais est-il question ces jours-ci?quelques millisecondes de différence?).La nouvelle façon de faire avec C# 6.0:

var p = new { FirstName = "Bill", LastName = "Gates" };
var fullname = $"{p.FirstName} {p.LastName}";

Cette nouvelle fonctionnalité est mieux, De l'OMI, et en fait de mieux dans notre cas comme nous l'avons codes où nous construisons querystrings dont la valeur dépend de certains facteurs.Imaginez une querystring où nous avons 6 arguments.Donc au lieu de faire un, par exemple:

var qs = string.Format("q1={0}&q2={1}&q3={2}&q4={3}&q5={4}&q6={5}", 
    someVar, anotherVarWithLongName, var3, var4, var5, var6)

peut être écrit comme cela et c'est plus facile à lire:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";

À partir de C# 6.0 interpolées chaînes peut être utilisé pour ce faire, ce qui simplifie le format encore plus.

var name = "Bill";
var surname = "Gates";
MessageBox.Show($"Welcome to the show, {name} {surname}!");

Une interpolation expression de chaîne qui ressemble à un modèle de chaîne de caractères qui contient des expressions.Une interpolation expression de chaîne crée une chaîne en remplaçant le contenu des expressions avec le ToString represenations des expressions’ résultats.

Interpolées chaînes ont des performances similaires à la Chaîne.Format, mais l'amélioration de la lisibilité et de la syntaxe plus courte, en raison du fait que les valeurs et les expressions sont insérés en ligne.

Veuillez également vous référer à cette dotnetperls article sur la chaîne d'interpolation.

Si vous êtes à la recherche d'une méthode par défaut pour le format de vos chaînes, ce qui a du sens en termes de lisibilité et de la performance (sauf si microsecondes va faire une différence dans votre cas d'utilisation spécifiques).

  1. Le formatage est l' “.NET” façon de faire.Certains outils de refactoring (Refactor!pour un) va même proposer de revoir la méthode concat style de code pour utiliser le style de mise en forme.
  2. Mise en forme est plus facile à optimiser pour le compilateur (bien que la deuxième sera probablement remaniée à utiliser le "Concat" la méthode qui est rapide).
  3. Mise en forme est généralement plus clair à lire (surtout avec “fancy” mise en forme).
  4. Mise en forme des moyens implicites appelle à".ToString' sur toutes les variables, ce qui est bon pour des raisons de lisibilité.
  5. Selon “Effective C#”, l' .NET "WriteLine" et "Format" des implémentations sont foiré, ils autobox tous les types de valeur (ce qui est mauvais).“Efficace C#”, conseille à jouer".ToString' appelle explicitement, ce qui à mon humble avis est faux (voir Jeff affichage)
  6. Pour le moment, la mise en forme de type conseils ne sont pas vérifiées par le compilateur, entraînant des erreurs d'exécution.Cependant, ceci peut être modifié dans les versions futures.

J'avais utilisation de la Chaîne.Format, mais je voudrais aussi avoir le format des chaînes de caractères dans les fichiers de ressources de sorte qu'il peut être localisée pour d'autres langues.À l'aide d'un simple string concat ne vous permettra pas de le faire.Évidemment, si vous ne avez besoin de localiser cette chaîne, ce n'est pas une raison pour penser.Cela dépend vraiment de ce que la chaîne est pour.

Si il va être montré à l'utilisateur, j'aimerais utiliser des chaînes de caractères.Format afin que je puisse localiser si j'en ai besoin - et FxCop va vérifier l'orthographe pour moi, juste au cas où :)

Si elle contient les numéros de téléphone ou de toute autre non-chaîne de choses (par ex.les dates), j'aimerais utiliser des chaînes de caractères.Format car il me donne plus de de contrôle sur le formatage.

Si c'est pour construire une requête SQL, je ne l'utiliserais Linq.

Si, pour une concaténation de chaînes à l'intérieur d'une boucle, je ne l'utiliserais StringBuilder pour éviter des problèmes de performance.

Si c'est pour une sortie à l'utilisateur l'habitude de voir, et ne va pas à l'effet de la performance que j'avais utiliser des chaînes de caractères.Format parce que je suis dans l'habitude de l'utiliser de toute façon et je suis utilisé pour elle :)

Si vous avez affaire à quelque chose qui doit être facile à lire (et c'est la plupart du code), je collerais avec l'opérateur surcharge version, à MOINS que:

  • Le code doit être exécuté pour des millions de fois
  • Vous êtes en train de faire des tonnes de concats (plus de 4, c'est une tonne)
  • Le code est orientée vers le Compact Framework

En vertu d'au moins deux de ces circonstances, je voudrais utiliser StringBuilder à la place.

- Je choisir en fonction de la lisibilité.Je préfère l'option de format quand il y a un peu de texte autour de l'variables.Dans cet exemple:

Console.WriteLine("User {0} accessed {1} on {2}.", 
                   user.Name, fileName, timestamp);

vous comprenez le sens même sans les noms de variables, alors que la méthode concat est encombré avec des citations et des signes + et confond mes yeux:

Console.WriteLine("User " + user.Name + " accessed " + fileName + 
                  " on " + timestamp + ".");

(J'ai emprunté de Mike exemple parce que je l'aime)

Si la chaîne de format ne veut pas dire grand chose sans les noms de variable, je dois utiliser concat:

   Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

L'option de format me fait lire les noms de variables et les mapper sur les numéros correspondants.La méthode concat option ne nécessite pas que.Je suis toujours confus par les citations et les signes+, mais l'alternative est pire.Ruby?

   Console.WriteLine(p.FirstName + " " + p.LastName);

Performance sage, j'attends l'option de format à être plus lent que la concat, depuis format nécessite la chaîne à analysée.Je ne me souviens pas avoir à optimiser ce genre de cours, mais si je le faisais, je regarderais string des méthodes comme Concat() et Join().

L'autre avantage avec le format est que la chaîne de format peut être mis dans un fichier de configuration.Très pratique avec des messages d'erreur et le texte de l'INTERFACE utilisateur.

Si vous avez l'intention de localiser le résultat, puis de la Chaîne.Le Format est essentiel parce que les différentes langues naturelles pourrait même ne pas avoir les données dans le même ordre.

Je pense que cela dépend fortement de la complexité de la sortie est.J'ai tendance à choisir selon le scénario fonctionne mieux à l'époque.

Choisir le bon outil basé sur le travail :D Selon ce qui semble plus propre!

Je préfère la deuxième mais je n'ai pas d'arguments rationnels à cette époque à l'appui de cette position.

Nice one!

Juste ajouté

        s.Start();
        for (var i = 0; i < n; i++)
            result = string.Concat(p.FirstName, " ", p.LastName);
        s.Stop();
        ceElapsedMilliseconds = s.ElapsedMilliseconds;
        ceElapsedTicks = s.ElapsedTicks;
        s.Reset();

Et il est encore plus rapide (je suppose que chaîne de caractères.Concat est appelé dans les deux exemples, mais le premier exige une sorte de traduction).

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 249ms - 3571621 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 65ms - 944948 ticks
1000000 x result = string.Concat(p.FirstName, " ", p.LastName); took: 54ms - 780524 ticks

Depuis, je ne pense pas que les réponses couvrent tout, j'aimerais faire un petit plus ici.

Console.WriteLine(string format, params object[] pars) appels string.Format.Le " + " implique la concaténation de chaîne.Je ne pense pas que cela a toujours à voir avec le style;J'ai tendance à mélanger les deux styles selon le contexte je suis.

Réponse courte

La décision que vous êtes en face de a à faire avec de la ficelle de répartition.Je vais essayer de faire simple.

Disons que vous avez

string s = a + "foo" + b;

Si vous l'exécutez, il va évaluer comme suit:

string tmp1 = a;
string tmp2 = "foo" 
string tmp3 = concat(tmp1, tmp2);
string tmp4 = b;
string s = concat(tmp3, tmp4);

tmp ici n'est pas vraiment une variable locale, mais c'est temporaire pour le JIT (il est poussé sur le IL de la pile).Si vous appuyez sur une chaîne de caractères sur la pile (comme ldstr dans IL pour les littéraux), vous mettez une référence à un pointeur de chaîne sur la pile.

Le moment où vous appelez concat cette référence devient un problème, car il n'y a pas de chaîne de référence qui contient à la fois des chaînes de caractères.Cela signifie que .NET a besoin d'allouer un bloc de mémoire, puis de le remplir avec les deux cordes.La raison de ce problème, c'est parce que la répartition est relativement cher.

Ce qui change la question:Comment pouvez-vous réduire le nombre de concat les opérations?

Ainsi, la rudesse de la réponse est: string.Format pour >1 concats, '+' fonctionnent très bien pour 1 concat.Et si vous n'aimez pas au sujet de faire des micro-optimisations des performances, string.Format fonctionnent très bien dans le cas général.

Une remarque à propos de la Culture

Et puis, il y a quelque chose qui s'appelle la culture...

string.Format vous permet d'utiliser CultureInfo dans votre mise en forme.Un simple opérateur '+' utilise de la culture actuelle.

C'est surtout une remarque importante si vous êtes en train de rédiger les formats de fichiers et f.ex. double les valeurs que vous 'ajouter' pour une chaîne de caractères.Sur des machines différentes, vous pourriez vous retrouver avec des cordes différentes si vous ne l'utilisez pas string.Format explicite CultureInfo.

F. ex.examinons ce qui se passe si vous modifiez un '.' pour ',' lors de l'écriture de votre séparées des virgules fichier de valeurs...en néerlandais, le séparateur décimal est une virgule, de sorte que votre utilisateur pourrait juste avoir une drôle de surprise.

De plus amples répondre

Si vous ne connaissez pas la dimension exacte de la chaîne d'avance, il est préférable d'utiliser une politique de ce genre pour overallocate les tampons que vous utilisez.Le manque d'espace est rempli en premier, après quoi les données sont copiées dans.

La croissance attribution d'un nouveau bloc de mémoire et de copier les anciennes données pour le nouveau tampon.L'ancien bloc de mémoire peut être libéré.Vous obtenez la ligne de fond à ce point:la croissance, est une opération coûteuse.

Le moyen le plus pratique de le faire est d'utiliser une surutilisation de la politique.Le plus commun de la politique est de overallocate tampons en puissances de 2.Bien sûr, vous avez à faire un peu plus intelligent que cela (car il n'a pas de sens à se développer à partir 1,2,4,8 si vous savez déjà que vous devez 128 caractères), mais vous obtenez l'image.La politique fait en sorte que vous n'avez pas besoin d'un trop grand nombre d'opérations coûteuses que j'ai décrit ci-dessus.

StringBuilder est une classe qui, en gros, overallocates le sous-jacent de la mémoire tampon dans les puissances de deux. string.Format utilise StringBuilder sous le capot.

Cela rend votre décision d'un base trade-off entre overallocate-et-append (multiple) (w/w).o.de la culture) ou tout simplement allouer-et-append.

Personnellement, la deuxième comme tout ce que vous utilisez est dans l'ordre direct, il sera de sortie dans.Alors qu'avec la première, vous devez faire correspondre le {0} et {1} avec le bon var, qui est facile à gâcher.

Au moins, il n'est pas aussi mauvais que le C++ sprintf où si vous obtenez le type de variable mal la chose va exploser.

Aussi, depuis la seconde est en ligne et il n'a pas à faire toute la recherche et le remplacement de tous les {0}, ce dernier point devrait être plus rapide...si je ne sais pas pour sûr.

En fait, j'aime la première, parce que quand il y a beaucoup de variables mêlé avec le texte, il semble plus facile à lire pour moi.De Plus, il est plus facile de traiter avec des guillemets lors de l'utilisation de la chaîne.Format(), euh, format.Voici analyse convenable de concaténation de chaîne.

J'ai toujours été à la chaîne.Format() de l'itinéraire.Être en mesure de formats de magasin, des variables comme Nathan exemple est un grand avantage.Dans certains cas, je peut ajouter une variable, mais une fois de plus de 1 variables concaténées je refactoriser à utiliser la mise en forme.

Oh, et juste pour être complet, voici quelques tiques plus vite que la normale concaténation:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));

La première (format) semble meilleure pour moi.C'est plus lisible et vous n'êtes pas en créant une chaîne temporaire des objets.

J'étais curieux de savoir où StringBuilder se avec ces tests.Les résultats ci-dessous...

class Program {
   static void Main(string[] args) {

      var p = new { FirstName = "Bill", LastName = "Gates" };

      var tests = new[] {
         new { Name = "Concat", Action = new Action(delegate() { string x = p.FirstName + " " + p.LastName; }) },
         new { Name = "Format", Action = new Action(delegate() { string x = string.Format("{0} {1}", p.FirstName, p.LastName); }) },
         new { Name = "StringBuilder", Action = new Action(delegate() {
            StringBuilder sb = new StringBuilder();
            sb.Append(p.FirstName);
            sb.Append(" ");
            sb.Append(p.LastName);
            string x = sb.ToString();
         }) }
      };

      var Watch = new Stopwatch();
      foreach (var t in tests) {
         for (int i = 0; i < 5; i++) {
            Watch.Reset();
            long Elapsed = ElapsedTicks(t.Action, Watch, 10000);
            Console.WriteLine(string.Format("{0}: {1} ticks", t.Name, Elapsed.ToString()));
         }
      }
   }

   public static long ElapsedTicks(Action ActionDelg, Stopwatch Watch, int Iterations) {
      Watch.Start();
      for (int i = 0; i < Iterations; i++) {
         ActionDelg();
      }
      Watch.Stop();
      return Watch.ElapsedTicks / Iterations;
   }
}

Résultats:

Concat: 406 ticks
Concat: 356 ticks
Concat: 411 ticks
Concat: 299 ticks
Concat: 266 ticks
Format: 5269 ticks
Format: 954 ticks
Format: 1004 ticks
Format: 984 ticks
Format: 974 ticks
StringBuilder: 629 ticks
StringBuilder: 484 ticks
StringBuilder: 482 ticks
StringBuilder: 508 ticks
StringBuilder: 504 ticks

Selon la CMDD prep matériel, Microsoft suggère d'utiliser l'opérateur + lorsque vous traitez avec un très petit nombre de concaténations (probablement 2 à 4).Je ne sais pas encore pourquoi, mais c'est quelque chose à considérer.

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