StringWriter ou StringBuilder

Quelle est la différence entre StringWriter et StringBuilder et quand dois-je utiliser l'un ou l'autre?

62
demandé sur Andrew Tobilko 2009-03-02 16:04:53

7 réponses

Je ne pense pas que les réponses existantes répondent vraiment à la question. La relation réelle entre les deux classes est un exemple de l'adaptateur modèle .

StringWriter implémente toutes ses méthodes Write... en transmettant à une instance de StringBuilder qu'elle stocke dans un champ. Ce n'est pas seulement un détail interne, parce que StringWriter a une méthode publique GetStringBuilder qui renvoie l'interne générateur de chaîne, et aussi constructeur qui vous permet de passer dans un StringBuilder .

So StringWriter est un adaptateur qui permet d'utiliser StringBuilder comme cible par code qui prévoit de fonctionner avec un TextWriter . En termes de comportement il n'y a clairement rien à choisir entre eux... a moins que vous ne puissiez mesurer la charge de transmission des appels, dans ce cas StringWriter est légèrement plus lent, mais cela semble très peu de chances d'être important.

alors pourquoi n'ont-ils pas fait StringBuilder implémenter TextWriter directement? Il s'agit d'une zone d'ombre, car l'intention derrière une interface n'est pas toujours évidente à première vue.

TextWriter est très près une interface de quelque chose qui accepte un flux de caractères. Mais il a une ride supplémentaire: une propriété appelée encodant . Cela implique que TextWriter est une interface vers quelque chose qui accepte un flux de caractères et les convertit aussi en octets .

c'est un vestige inutile dans StringWriter parce qu'il n'effectue aucun encodage. La documentation dit:

cette propriété est nécessaire pour certains scénarios XML où un en-tête doit être écrit contenant l'encodage utilisé par le StringWriter. Ce permettre le code XML pour consommer un StringWriter arbitraire et générer l'en-tête XML correct.

mais cela ne peut pas être juste, parce qu'il n'y a aucun moyen pour nous de spécifier la valeur de Encoding pour StringWriter . La propriété a toujours la valeur UnicodeEncoding . Par conséquent, tout code qui examinerait cette propriété pour créer un en-tête XML dirait toujours utf-16 . Par exemple:

var stringWriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(stringWriter))
    xDocument.WriteTo(xmlWriter);

qui produit l'en-tête:

<?xml version="1.0" encoding="utf-16"?>

Que faire si vous avez utilisé fichier.WriteAllText pour écrire votre chaîne de caractères XML dans un fichier? Par défaut, vous avez alors un fichier utf-8 avec un en-tête utf-16 .

Dans de tels scénarios, il serait plus sûr d'utiliser StreamWriter , et de le construire avec un chemin d'accès au fichier, ou un FileStream , ou si vous voulez examiner les données, puis utiliser un MemoryStream et donc obtenir un tableau d'octets . Tous ces les combinaisons garantiraient que le codage aux octets et la génération d'en-tête étaient guidés par la même valeur Encoding dans votre StreamWriter .

le but de la propriété Encoding était de permettre aux générateurs de flux de caractères d'inclure des informations précises sur l'encodage dans le flux de caractères lui-même (comme dans L'exemple XML; d'autres exemples incluent des en-têtes de courriel, et ainsi de suite).

mais en introduisant StringWriter , que le lien entre la génération de contenu et l'encodage est rompu, et de tels mécanismes automatiques cessent de fonctionner et deviennent potentiellement sujets à des erreurs.

néanmoins, StringWriter est un adaptateur utile si vous êtes prudent, c'est-à-dire que vous comprenez que votre code de génération de contenu ne doit pas dépendre de la valeur insignifiante de la propriété Encoding . Mais ce genre de mise en garde est souvent associée avec l'adaptateur modèle. Il est souvent une sorte de hack pour vous permettre d'adapter un presque carré, mais presque rond dans un trou rond.

77
répondu Daniel Earwicker 2012-06-15 10:29:28

StringWriter découle de TextWriter , ce qui permet à diverses classes d'écrire des textes sans se soucier de leur destination. Dans le cas de StringWriter , la sortie est juste dans la mémoire. Vous l'utiliserez si vous appelez une API qui a besoin d'un TextWriter mais vous ne voulez accumuler des résultats qu'en mémoire.

StringBuilder est essentiellement un tampon qui vous permet d'effectuer plusieurs opérations (généralement ajoute) à une "chaîne logique" sans créer un nouvel objet string à chaque fois. Vous pourrez construire une chaîne de multiples opérations.

54
répondu Jon Skeet 2009-03-02 13:13:32

S'appuyant sur les (bonnes) réponses précédentes, StringWriter est en fait beaucoup plus polyvalent que StringBuilder, fournissant beaucoup de surcharges.

par exemple:

Alors que Stringbuilder accepte uniquement un string ou rien pour Appendline

StringBuilder sb = new StringBuilder();
sb.AppendLine("A string");

StringWriter peut prendre un format de chaîne directement

StringWriter sw = new StringWriter();
sw.WriteLine("A formatted string {0}", DateTime.Now);

Avec StringBuilder l'on doit faire (ou utiliser des chaînes de caractères.Format, ou $"")

sb.AppendFormat("A formatted string {0}", DateTime.Now);
sb.AppendLine();

de ne Pas le faire ou mourir de choses, mais encore une différence

4
répondu Johan Sonesson 2015-07-22 09:49:39

la classe StringBuilder est fondamentalement une chaîne mutable, une classe d'aide à construire une chaîne immuable. Le StringWriter est construit sur le dessus pour ajouter des fonctions plus pratiques pour le formatage de chaîne.

3
répondu Konrad Rudolph 2009-03-02 13:09:46

a StringWriter est utilisé pour écrire le texte à un fichier mémoire et un StringBuilder est utilisé pour ajouter des chaînes ensemble dans une mémoire efficace.

2
répondu Andrew Hare 2009-03-02 13:19:02

StringBuilder et StringReader sont utilisés pour améliorer la performance dans des situations différentes.

utilisez StringBuilder pour améliorer la performance sur la manipulation de chaîne telle que la concaténation, la modification de chaîne de façon répétée.

Random rnd = new Random();
StringBuilder sb = new StringBuilder();

// Generate 10 random numbers and store in sb.
for (int i = 0; i < 10; i++)
{
    sb.Append(rnd.Next().ToString("N5"));
}
Console.WriteLine("The original string:");
Console.WriteLine(sb.ToString());

// Decrease each number by one.
for (int ctr = 0; ctr < sb.Length; ctr++)
{
    if (Char.GetUnicodeCategory(sb[ctr]) == System.Globalization.UnicodeCategory.DecimalDigitNumber)
    {
        int number = (int)Char.GetNumericValue(sb[ctr]);
        number--;
        if (number < 0)
            number = 9;

        sb[ctr] = number.ToString()[0];
    }
}
Console.WriteLine("\nThe new string:");
Console.WriteLine(sb.ToString());

utilisez StringReader pour analyser une grande quantité de texte dans des lignes séparées et minimiser l'utilisation de la mémoire pendant le traitement des données. Voir l'exemple suivant où la méthode ReadLine sur StringReader scanne simplement la nouvelle ligne à partir de la position actuelle, puis renvoie un sbstring basé sur le champ string.

using (StringReader sr = new StringReader("input.txt"))
{
    // Loop over the lines in the string or txt file.
    int count = 0;
    string line;
    while((line = sr.ReadLine()) != null)
    {
        count++;
        Console.WriteLine("Line {0}: {1}", count, line);
    }
}
1
répondu Serge Voloshenko 2016-11-13 01:48:02

StringBuilder est utilisé pour la concaténation de la corde de masse. Il est plus efficace pour plus de 5 cordes, autant que je sache, puis String.Concat() . Il peut également être utilisé avec un format spécifique ( .AppendFormat() )

0
répondu abatishchev 2016-08-12 15:25:02