En el primer artículo sobre Strings dijimos que son inmutables y que modificarlos crea un nuevo String (con los problemas de velocidad y consumo de memoria que supone).
*Pero que pasa si tengo que unir 10,000 palabras?
Si usas un String normal, tu programa se va a resentir. Aquí es donde entra en juego el rendimiento: de StringBuilder.
El problema de la concatenación
Imaginad este escenario:
string texto = "";
for (int i = 0; i < 10000; i++)
{
texto += i.ToString(); // ¡¡ERROR DE RENDIMIENTO!! //
}
En cada vuelta del bucle, C# tiene que:
- Copiar el string viejo.
- Añadir el nuevo carácter.
- Crear un objeto nuevo.
- Tirar el viejo.
¿Muy eficiente no parece verdad? No, no lo es.
La Solución System.Text.StringBuilder
StringBuilder es una clase diseñada para ser mutable. Es decir, un String que puede cambiar.
Funciona internamente con una Array dinámico de caracteres que tiene una capacidad extra (un buffer). Cuando añades texto, simplemente rellena los huecos vacíos de ese array. No crea objetos nuevos.
Si el array se llena, StringBuilder crea uno nuevo (generalmente el doble de grande), copia los datos y sigue. Esto ocurre muy pocas veces comparado con la concatenación normal.
Esto es la máxima optimización posible en manipulación de texto.
No os volváis locos cambiando todos vuestros string por StringBuilder. StringBuilder tiene un coste de inicialización y no tiene la seguridad de la inmutabilidad.
- Si vas a concatenar 3 o 4 cosas Usa
string + stringo interpolación$"{a}{b}". Es más rápido y legible. - Si vas a concatenar dentro de un bucle cientos o miles de veces, usa
StringBuilder.
Cómo se usa StringBuilder
StringBuilder se encuentra en el espacio de nombres System.Text.
using System.Text;
StringBuilder sb = new StringBuilder();
sb.Append("Hola");
sb.Append(" ");
sb.AppendLine("Mundo"); // Añade y salta de línea
sb.AppendFormat("El valor es {0}", 100);
// Al final, convertimos a String inmutable
string resultado = sb.ToString();
Alguno de sus métodos principales son.
Append(): Añade al final.AppendLine(): Añade al final con salto de línea.Insert(index, valor): Inserta en una posición (más costoso, tiene que mover elementos).Remove(index, length): Borra una parte.Clear(): Limpia el contenido para reutilizar la instancia.
Optimización de la capacidad
Si sabéis de antemano (o más o menos) cuánto va a ocupar vuestro texto final, podéis pasárselo al constructor para evitar que tenga que redimensionar el array interno.
// Crea un buffer inicial de 1000 caracteres
StringBuilder sb = new StringBuilder(1000);
