.net - StringWriter o StringBuilder
(7)
¿Cuál es la diferencia entre StringWriter
y StringBuilder
y cuándo debería usar uno u otro?
La clase StringBuilder
es básicamente una cadena mutable, una clase auxiliar para construir una cadena inmutable. El StringWriter
está construido en la parte superior para agregar más funciones de conveniencia para el formateo de cadenas.
No creo que ninguna de las respuestas existentes realmente responda la pregunta. La relación real entre las dos clases es un ejemplo del patrón de adaptador .
StringWriter
implementa todos sus métodos de Write...
reenviando a una instancia de StringBuilder
que almacena en un campo. Esto no es simplemente un detalle interno, porque StringWriter
tiene un método público GetStringBuilder que devuelve el generador de cadenas interno, y también un constructor que le permite pasar un StringBuilder
existente.
Así que StringWriter
es un adaptador que permite que StringBuilder
se use como un destino por código que espera trabajar con un TextWriter
. En términos de comportamiento básico, claramente no hay nada que elegir entre ellos ... a menos que pueda medir la sobrecarga de reenviar las llamadas, en cuyo caso StringWriter
es un poco más lento, pero parece muy poco probable que sea significativo.
Entonces, ¿por qué no hicieron que StringBuilder
implementara TextWriter
directamente? Esta es un área gris, porque la intención detrás de una interfaz no siempre es clara a primera vista.
TextWriter
es casi una interfaz para algo que acepta una secuencia de caracteres. Pero tiene una arruga adicional: una propiedad llamada Encoding . Esto implica que TextWriter
es una interfaz para algo que acepta una secuencia de caracteres y también los convierte en bytes .
Esto es un vestigio inútil en StringWriter
porque no realiza codificación. La Encoding dice:
Esta propiedad es necesaria para algunos escenarios XML donde se debe escribir un encabezado que contenga la codificación utilizada por StringWriter. Esto permite que el código XML consuma un StringWriter arbitrario y genere el encabezado XML correcto.
Pero eso no puede ser correcto, porque no hay forma de que especifiquemos el valor de Encoding
for StringWriter
. La propiedad siempre tiene el valor UnicodeEncoding
. En consecuencia, cualquier código que examinara esta propiedad para construir un encabezado XML siempre diría utf-16
. Por ejemplo:
var stringWriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(stringWriter))
xDocument.WriteTo(xmlWriter);
Eso produce el encabezado:
<?xml version="1.0" encoding="utf-16"?>
¿Qué File.WriteAllText si usa File.WriteAllText para escribir su cadena XML en un archivo? Por defecto, tendrías un archivo utf-8
con un encabezado utf-16
.
En tales escenarios, sería más seguro usar StreamWriter
, y construirlo con una ruta de archivo, o un FileStream
, o si desea examinar los datos, utilice un MemoryStream
y obtenga una matriz de bytes . Todas estas combinaciones garantizarían que la codificación en bytes y la generación del encabezado estuvieran guiadas por el mismo valor de Encoding
en su StreamWriter
.
El objetivo de la propiedad Encoding
era permitir que los generadores de secuencias de caracteres incluyeran información precisa sobre la codificación en la secuencia de caracteres en sí (como en el ejemplo XML, otros ejemplos incluyen encabezados de correo electrónico, etc.).
Pero al introducir StringWriter
, ese vínculo entre la generación de contenido y la codificación se rompe, por lo que dichos mecanismos automáticos dejan de funcionar y se vuelven potencialmente propensos a errores.
Sin embargo, StringWriter
es un adaptador útil si tiene cuidado, es decir, comprende que su código de generación de contenido no debe depender del valor sin sentido de la propiedad de Encoding
. Pero ese tipo de advertencia comúnmente se asocia con el patrón del adaptador. A menudo es una especie de truco que te permite colocar una clavija cuadrada casi redonda en un agujero redondo.
Sobre la base de las respuestas (buenas) anteriores, StringWriter es en realidad mucho más versátil que StringBuilder, proporcionando muchas sobrecargas.
Por ejemplo:
Mientras que Stringbuilder solo acepta una cadena o nada para Appendline
StringBuilder sb = new StringBuilder();
sb.AppendLine("A string");
StringWriter puede tomar un formato de cadena directamente
StringWriter sw = new StringWriter();
sw.WriteLine("A formatted string {0}", DateTime.Now);
Con StringBuilder uno debe hacer esto (o usar string.Format, o $ "")
sb.AppendFormat("A formatted string {0}", DateTime.Now);
sb.AppendLine();
No hacer o morir cosas, pero aún así una diferencia
Un StringWriter
se utiliza para escribir texto en un archivo memoria y un StringBuilder
se utiliza para agregar cadenas juntas de una manera eficiente de la memoria.
StringWriter
deriva de TextWriter
, que permite que varias clases escriban texto sin importar a dónde va. En el caso de StringWriter
, la salida solo está en la memoria. TextWriter
usar esto si está llamando a una API que necesita un TextWriter
pero solo desea generar resultados en la memoria.
StringBuilder
es esencialmente un búfer que le permite realizar varias operaciones (generalmente se agrega) a una "cadena lógica" sin crear un nuevo objeto de cadena cada vez. Lo usarías para construir una cadena en múltiples operaciones.
StringBuilder
se utiliza para la concatenación masiva de cadenas. Es más efectivo para más de 5 cuerdas, hasta donde sé, entonces String.Concat()
. También se puede usar con un formato específico ( .AppendFormat()
)
StringBuilder
y StringReader
se utilizan para mejorar el rendimiento en diferentes situaciones.
Utilice StringBuilder
para mejorar el rendimiento en la manipulación de cadenas, como la concatenación, la modificación de cadenas repetidamente.
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());
Use StringReader
para analizar una gran cantidad de texto en líneas separadas y minimizar el uso de memoria mientras procesa datos. Vea el siguiente ejemplo donde el método ReadLine en StringReader simplemente busca la próxima línea nueva comenzando en la posición actual, y luego regresa una cadena basada en la cadena del campo.
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);
}
}