127 votes

Quand est-il préférable d’utiliser la concaténation de chaînes String.Format vs ?

J’ai un petit morceau de code qui est l’analyse d’une valeur d’index pour déterminer une entrée de cellule dans Excel. Il m’a fait penser...

Quelle est la différence entre

et

Est une « meilleure » que l’autre ? Et pourquoi ?

164voto

Dan C. Points 2115

Ma préférence initiale (venant d'un C++ arrière-plan) a été pour la Chaîne.Format. J'ai abandonné plus tard pour les raisons suivantes:

  • La concaténation de chaîne est sans doute "plus sûr". Il m'est arrivé (et je l'ai vu arriver plusieurs autres développeurs) pour supprimer un paramètre, ou gâcher le paramètre d'ordre par erreur. Le compilateur ne vérifie pas les paramètres par rapport à la chaîne de format et vous vous retrouvez avec une erreur d'exécution (qui est, si vous êtes assez chanceux de ne pas l'avoir dans un obscur méthode, telle que l'enregistrement d'une erreur). Avec la concaténation, la suppression d'un paramètre est moins sujette aux erreurs. On pourrait soutenir que le risque d'erreur est très faible, mais il peut arriver.

- La concaténation de chaîne autorise les valeurs null, String.Format ne le sont pas. L'écriture "s1 + null + s2" ne rompt pas, il vient de traite de la valeur null comme une Chaîne de caractères.Vide. Eh bien, cela dépend de votre scénario spécifique - il y a des cas où vous souhaitez une erreur au lieu de l'ignorer silencieusement null Prénom. Cependant, même dans cette situation, je préfère personnellement la vérification pour les valeurs null moi-même et en jetant les erreurs spécifiques au lieu de la norme ArgumentNullException je reçois de la Chaîne.Format.

  • La concaténation de chaîne fonctionne mieux. Certains des postes ci-dessus déjà le mentionner (sans vraiment expliquer pourquoi, ce qui me décida à écrire ce post :).

C'est l'idée .NET compilateur est assez intelligent pour convertir ce morceau de code:

public static string Test(string s1, int i2, int i3, int i4, 
        string s5, string s6, float f7, float f8)
{
    return s1 + " " + i2 + i3 + i4 + " ddd " + s5 + s6 + f7 + f8;
}

pour cela:

public static string Test(string s1, int i2, int i3, int i4,
            string s5, string s6, float f7, float f8)
{
    return string.Concat(new object[] { s1, " ", i2, i3, i4, 
                    " ddd ", s5, s6, f7, f8 });
}

Ce qui se passe sous le capot de la Chaîne.Concat est facile à deviner (utilisation du Réflecteur). Les objets dans le tableau est converti à leur chaîne via ToString(). Ensuite, la longueur totale est calculée et qu'une chaîne allouée (avec la longueur totale). Enfin, chaque chaîne est copié dans la chaîne résultante via wstrcpy dans certains dangereux morceau de code.

Raisons String.Concat est plus rapide? Eh bien, nous pouvons tous avoir un coup d'oeil ce qu' String.Format - vous serez surpris par la quantité de code nécessaire au processus de la chaîne de format. Sur le dessus de cela (j'ai vu des commentaires au sujet de la consommation de mémoire), String.Format utilise un StringBuilder en interne. Voici comment:

StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));

Ainsi, pour chaque argument passé, il se réserve de 8 caractères. Si l'argument est une valeur d'un seul chiffre, alors tant pis, nous avons un espace gaspillé. Si l'argument est un objet personnalisé de retour texte très long sur ToString(), alors il pourrait y avoir encore quelques réaffectation nécessaire (le pire scénario, bien sûr).

Par rapport à cela, la concaténation uniquement les déchets de l'espace de l'objet array (pas trop, en tenant compte, c'est un tableau de références). Il n'y a pas d'analyse pour les spécificateurs de format et pas d'intermédiaire StringBuilder. Le boxing/unboxing de surcharge est présente dans les deux méthodes.

La seule raison pour laquelle j'irais pour la Chaîne.Le Format est lorsque la localisation est impliqué. Mettre chaînes de formatage de ressources permet de prendre en charge différentes langues sans vous embêter avec le code (penser à des scénarios où les valeurs mises en forme la modification de la commande en fonction de la langue, c'est à dire "après {0} heures et {1} minutes" peut paraître très différente en Japonais :).


Pour résumer mon premier (et très long) post:

  • meilleur moyen (en termes de rapport performances / maintenabilité/lisibilité) pour moi, c'est à l'aide de la concaténation de chaîne, sans ToString() appels
  • si vous êtes après de la performance, faire l' ToString() des appels vous-même pour éviter de boxe (je suis un peu biaisé vers plus de lisibilité) - même en tant que première option dans votre question
  • si vous êtes montrant les chaînes localisées pour l'utilisateur (pas le cas ici), String.Format() a un bord.

120voto

Jon Skeet Points 692016

Pour être honnête, je pense que la première version est plus simple - même si j’ai de simplifierait :

Je soupçonne que d’autre réponses peuvent parler de la baisse de performance, mais pour être honnête, ça va être un minimum s’il est présent à tous - et cette version de concaténation n’a pas besoin d’analyser la chaîne de format.

Chaînes de format sont parfaits pour des fins de localisation etc., mais dans un cas comme cette concaténation est plus simple et fonctionne aussi bien.

8voto

RoadWarrior Points 11588

Je pense que ce lien MSDN est un résumé raisonnable. Jon Skeet a également une entrée de blog intéressant sur le sujet

6voto

Je pense que la première option est plus lisible et qui doit être votre principale préoccupation.

xlsSheet.Write("C" + rowIndex.ToString(), null, title);

chaîne de caractères.Format utilise un StringBuilder sous le capot (vérifier avec réflecteur) afin de ne pas avantage, sauf si vous faites une quantité importante de concaténation. Il sera plus lent pour votre scénario, mais la réalité est la micro-optimisation de la performance décision est inapproprié plupart du temps, et vous devriez vraiment se concentrer sur la lisibilité de votre code, sauf si vous êtes dans une boucle.

De toute façon, écrire pour des raisons de lisibilité d'abord et ensuite utiliser un profileur de performance afin d'identifier vos points chauds si vous pensez vraiment que vous avez des problèmes de rendement.

5voto

P Daddy Points 14228

Pour un cas simple où c'est une simple concaténation, j'ai l'impression que ça n'en vaut pas la complexité de l' string.Format (et je n'ai pas testé, mais je suppose que pour un cas simple comme ça, string.Format peut - être un peu plus lent, ce qui avec la chaîne de format d'analyse et de tous). Comme Jon Skeet, je préfère ne pas appeler explicitement .ToString(), depuis qui sera fait de façon implicite par l' string.Concat(string, object) de surcharge, et je pense que le code est plus propre et d'apparence plus facile à lire sans elle.

Mais pour plus de quelques enchaînements (combien est subjectif), je préfère largement string.Format. À un certain point, je pense qu'à la fois la lisibilité et la performance de souffrir inutilement avec la concaténation.

Si il y a de nombreux paramètres à la chaîne de format (encore une fois, "beaucoup" est subjectif), je préfère inclure commenté indices sur le remplacement des arguments, de peur que je perds la trace de valeur pour le paramètre. Un exemple artificiel:

Console.WriteLine(
    "Dear {0} {1},\n\n" +

    "Our records indicate that your {2}, \"{3}\", is due for {4} {5} shots.\n" +
    "Please call our office at 1-900-382-5633 to make an appointment.\n\n" +

    "Thank you,\n" +
    "Eastern Vetinary",

    /*0*/client.Title,
    /*1*/client.LastName,
    /*2*/client.Pet.Animal,
    /*3*/client.Pet.Name,
    /*4*/client.Pet.Gender == Gender.Male ? "his" : "her",
    /*5*/client.Pet.Schedule[0]
);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X