Hasta ahora hemos trabajado con variables que almacenan un único dato: un título, un número
de páginas, un booleano. Pero en la práctica, casi cualquier programa necesita manejar
varios datos del mismo tipo a la vez —por ejemplo, todos los títulos de libros de
BiblioTech— y necesita también manipular texto de forma más avanzada que un simple
Console.WriteLine. En esta lección aprenderás a trabajar con arrays (una y varias
dimensiones), a recorrerlos con foreach/for, y a explotar toda la potencia de la clase
string: concatenación, interpolación, y sus métodos más habituales. Cerraremos con
StringBuilder, la herramienta adecuada cuando se concatena texto de forma repetida dentro de
un bucle.
Contenido
- Arrays de una dimensión
- Arrays de varias dimensiones
- Arrays de tamaño fijo frente a
List<T> - Recorrer un array con
foreachy confor - La clase
string: inmutabilidad, concatenación e interpolación - Métodos habituales de
string StringBuilderpara concatenación eficiente
Arrays de una dimensión
Un array es una colección de elementos del mismo tipo, almacenados de forma contigua y
accesibles mediante un índice numérico que empieza en 0. Se declara indicando el tipo de
los elementos seguido de corchetes []:
string[] titulosLibros = new string[3];
titulosLibros[0] = "Cien anos de soledad";
titulosLibros[1] = "Rayuela";
titulosLibros[2] = "Ficciones";
Console.WriteLine(titulosLibros[0]); // Cien anos de soledadTambién se puede declarar e inicializar en un solo paso, indicando directamente los valores:
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };
// Forma equivalente, más explícita:
string[] titulosLibrosB = new string[] { "Cien anos de soledad", "Rayuela", "Ficciones" };Tamaño fijo y propiedad Length
Una característica fundamental de los arrays en C# es que su tamaño se fija al crearlos y
no puede cambiar después. Para saber cuántos elementos contiene, se usa la propiedad
Length:
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };
Console.WriteLine(titulosLibros.Length); // 3Acceso fuera de rango
Intentar acceder a un índice que no existe (por ejemplo, titulosLibros[5] en un array de 3
elementos) no da un error al compilar, pero sí provoca un error en tiempo de ejecución
(una excepción de tipo IndexOutOfRangeException, que estudiaremos en el Módulo 2 al ver el
manejo de excepciones). Por eso siempre hay que asegurarse de que el índice usado esté entre
0 y Length - 1.
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };
// Console.WriteLine(titulosLibros[3]); // Error en tiempo de ejecución: índice fuera de rango
Console.WriteLine(titulosLibros[titulosLibros.Length - 1]); // Ficciones (el último elemento)Arrays de varias dimensiones
Además de los arrays de una dimensión (una simple lista de elementos), C# permite arrays de varias dimensiones, útiles para representar datos organizados en forma de tabla o cuadrícula. El caso más común es el array bidimensional (filas y columnas):
// Un array de 2 filas (estanterías) x 3 columnas (huecos por estantería)
string[,] estanteria = new string[2, 3];
estanteria[0, 0] = "Cien anos de soledad";
estanteria[0, 1] = "Rayuela";
estanteria[0, 2] = "Ficciones";
estanteria[1, 0] = "El Aleph";
estanteria[1, 1] = "Pedro Paramo";
estanteria[1, 2] = "La casa de los espiritus";
Console.WriteLine(estanteria[1, 2]); // La casa de los espiritusTambién se pueden inicializar directamente con sus valores:
string[,] estanteria =
{
{ "Cien anos de soledad", "Rayuela", "Ficciones" },
{ "El Aleph", "Pedro Paramo", "La casa de los espiritus" }
};Para conocer el número de filas y columnas de un array bidimensional se usa el método
GetLength, indicando la dimensión (0 para filas, 1 para columnas):
Console.WriteLine(estanteria.GetLength(0)); // 2 (filas / estanterías)
Console.WriteLine(estanteria.GetLength(1)); // 3 (columnas / huecos por estantería)En este curso los arrays multidimensionales aparecerán de forma puntual; la mayoría de los ejemplos usarán arrays de una dimensión, que son con diferencia los más habituales en el día a día.
Arrays de tamaño fijo frente a List<T>
Como hemos visto, un array tiene un tamaño fijo: una vez creado con, por ejemplo, 3 elementos, no se puede añadir un cuarto título de libro sin crear un array completamente nuevo. En muchos escenarios reales (como ir añadiendo libros al catálogo de BiblioTech a medida que se registran) esta limitación resulta incómoda.
Para esos casos, .NET ofrece List<T>, una colección cuyo tamaño puede crecer y encogerse de
forma dinámica, con métodos como Add (añadir un elemento) o Remove (quitarlo). Aquí solo la
mencionamos de pasada: List<T> y el resto de colecciones de .NET se estudian en profundidad
en el Módulo 4 ("Colecciones"), junto con LINQ, la potente herramienta de consulta que
usaremos para explorar el catálogo completo de BiblioTech. Por ahora, quédate con esta idea:
Array (string[]) |
List<T> (por ejemplo, List<string>) |
|
|---|---|---|
| Tamaño | Fijo al crearse | Dinámico (crece y decrece) |
| Cuándo usarlo | El número de elementos se conoce de antemano y no cambia | El número de elementos puede variar durante la ejecución |
| Se estudia en detalle en | Este módulo | Módulo 4 |
Recorrer un array con foreach y con for
Para procesar todos los elementos de un array, uno a uno, existen dos bucles principales. Aunque los bucles se estudian en profundidad en el Módulo 2 ("Bucles"), aquí veremos su uso básico aplicado a arrays, ya que es una combinación tan habitual que conviene conocerla desde ya.
foreach: recorrer todos los elementos
foreach recorre todos los elementos de una colección, uno detrás de otro, sin necesidad
de gestionar manualmente un índice:
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };
foreach (string titulo in titulosLibros)
{
Console.WriteLine(titulo);
}Este código imprime, uno por línea, cada título del array. foreach es la opción más clara
y recomendable cuando simplemente necesitas leer o procesar cada elemento, sin necesitar
su posición (índice).
for: recorrer con control explícito del índice
Cuando sí necesitas el índice (por ejemplo, para numerar los libros, o para modificar el
propio array durante el recorrido), se usa el bucle for, que da control explícito sobre un
contador:
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };
for (int i = 0; i < titulosLibros.Length; i++)
{
Console.WriteLine($"{i + 1}. {titulosLibros[i]}");
}Este ejemplo imprime cada título precedido de su posición en la lista, empezando en 1 (sumando 1 al índice, que empieza en 0):
foreach |
for |
|
|---|---|---|
| Acceso al índice | No (solo el valor de cada elemento) | Sí, mediante el contador (i) |
| Modificar el array durante el recorrido | No recomendable | Posible, con precaución |
| Legibilidad | Más simple y directo | Más flexible pero algo más verboso |
La clase string: inmutabilidad, concatenación e interpolación
Inmutabilidad
Una string en C# es inmutable: una vez creada, su contenido no puede modificarse.
Cualquier operación que "parezca" cambiar una cadena (como concatenarla con otro texto)
realmente crea una cadena nueva en memoria, dejando la original intacta:
string tituloOriginal = "Rayuela";
string tituloModificado = tituloOriginal + " (edicion especial)";
Console.WriteLine(tituloOriginal); // Rayuela (no ha cambiado)
Console.WriteLine(tituloModificado); // Rayuela (edicion especial)Esta propiedad tiene implicaciones importantes de rendimiento cuando se concatenan muchas
cadenas dentro de un bucle, como veremos más adelante en la sección de StringBuilder.
Concatenación
Concatenar significa unir dos o más cadenas en una sola. La forma más básica es con el
operador +:
string titulo = "Cien anos de soledad";
string autor = "Gabriel Garcia Marquez";
string descripcion = titulo + " - " + autor;
Console.WriteLine(descripcion); // Cien anos de soledad - Gabriel Garcia MarquezInterpolación de cadenas ($"")
La interpolación es una forma mucho más legible de construir cadenas que combinan texto
fijo con valores de variables. Se antepone el símbolo $ antes de las comillas, y las
variables (o incluso expresiones) se insertan directamente entre llaves { }:
string titulo = "Cien anos de soledad";
int paginas = 471;
bool disponible = true;
string resumen = $"El libro '{titulo}' tiene {paginas} paginas y esta disponible: {disponible}";
Console.WriteLine(resumen);Resultado:
Dentro de las llaves { } de una cadena interpolada se pueden escribir incluso pequeñas
expresiones, no solo variables sueltas:
int paginasLeidas = 120;
int totalPaginas = 471;
Console.WriteLine($"Progreso de lectura: {paginasLeidas} de {totalPaginas} paginas ({paginasLeidas * 100 / totalPaginas}%)");| Técnica | Ejemplo | Legibilidad |
|---|---|---|
Concatenación con + |
"Libro: " + titulo + ", paginas: " + paginas |
Se vuelve difícil de leer con muchas variables |
Interpolación $"" |
$"Libro: {titulo}, paginas: {paginas}" |
Clara incluso con varias variables |
En este curso preferiremos la interpolación siempre que combinemos texto con variables, por su claridad.
Métodos habituales de string
La clase string incluye numerosos métodos ya construidos para las tareas más habituales de
manipulación de texto. Estos son los más usados:
| Método | Qué hace | Ejemplo |
|---|---|---|
Split |
Divide una cadena en un array de subcadenas, según un separador | "a,b,c".Split(',') → ["a", "b", "c"] |
Trim |
Elimina espacios en blanco al principio y al final | " Rayuela ".Trim() → "Rayuela" |
Contains |
Comprueba si una cadena contiene otra | "Rayuela".Contains("ayu") → true |
Substring |
Extrae una parte de la cadena, indicando posición (y opcionalmente longitud) | "Rayuela".Substring(0, 3) → "Ray" |
ToUpper / ToLower |
Convierte toda la cadena a mayúsculas o minúsculas | "Rayuela".ToUpper() → "RAYUELA" |
Vamos a verlos aplicados a un ejemplo realista de BiblioTech: procesar una línea de texto con varios datos de un libro separados por comas, tal y como podría venir de un archivo de importación (algo que trataremos en profundidad en el Módulo 5, "Entrada/Salida de Archivos").
string lineaImportada = " Rayuela, Julio Cortazar, 635 ";
string lineaLimpia = lineaImportada.Trim(); // quita espacios sobrantes al principio/final
string[] campos = lineaLimpia.Split(','); // separa por comas: [" Rayuela", " Julio Cortazar", " 635 "]
string titulo = campos[0].Trim(); // "Rayuela"
string autor = campos[1].Trim(); // "Julio Cortazar"
string paginasTexto = campos[2].Trim(); // "635"
Console.WriteLine($"Titulo: {titulo}");
Console.WriteLine($"Autor: {autor}");
Console.WriteLine($"Paginas (texto): {paginasTexto}");
// Búsqueda de texto dentro de un título
bool contieneRay = titulo.Contains("Ray");
Console.WriteLine($"El titulo contiene 'Ray': {contieneRay}");
// Extraer las 3 primeras letras del título
string prefijoTitulo = titulo.Substring(0, 3);
Console.WriteLine($"Prefijo del titulo: {prefijoTitulo}");
// Normalizar a mayúsculas para comparaciones sin distinguir mayúsculas/minúsculas
string tituloEnMayusculas = titulo.ToUpper();
Console.WriteLine(tituloEnMayusculas); // RAYUELAFíjate en que cada uno de estos métodos no modifica la cadena original (recuerda: las cadenas son inmutables), sino que devuelve una cadena nueva con el resultado. Por eso siempre asignamos el resultado a una variable (o lo usamos directamente), en lugar de esperar que la variable original cambie por sí sola.
Comparación de cadenas ignorando mayúsculas/minúsculas
Un caso de uso muy habitual al buscar en un catálogo (como el de BiblioTech) es comparar
texto sin que importen las mayúsculas o minúsculas. Para ello se pueden convertir ambas
cadenas al mismo caso antes de comparar, o usar el método Equals con una opción específica:
string busqueda = "rayuela";
string tituloCatalogo = "Rayuela";
bool coincide = tituloCatalogo.Equals(busqueda, StringComparison.OrdinalIgnoreCase);
Console.WriteLine(coincide); // TrueStringBuilder para concatenación eficiente
Como cada string es inmutable, concatenar cadenas repetidamente dentro de un bucle (por
ejemplo, para construir un informe con todos los títulos del catálogo) crea, en cada
iteración, una cadena nueva completa en memoria, descartando la anterior. Para pocos elementos
esto no supone ningún problema, pero si el bucle se repite muchas veces (miles de libros, por
ejemplo), puede afectar notablemente al rendimiento.
Para estos casos, .NET ofrece la clase StringBuilder, pensada específicamente para construir
cadenas de texto de forma eficiente mediante sucesivas modificaciones, sin crear una cadena
nueva completa en cada paso. Se encuentra en el espacio de nombres System.Text.
using System.Text;
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph" };
StringBuilder informe = new StringBuilder();
informe.Append("Catalogo de BiblioTech:");
informe.AppendLine(); // salto de línea
foreach (string titulo in titulosLibros)
{
informe.AppendLine($"- {titulo}");
}
string informeFinal = informe.ToString();
Console.WriteLine(informeFinal);Resultado:
| Situación | Recomendación |
|---|---|
| Concatenar unas pocas cadenas, fuera de un bucle | + o interpolación $"" |
| Concatenar dentro de un bucle que puede repetirse muchas veces | StringBuilder |
No profundizaremos más en StringBuilder en este módulo introductorio; es una herramienta que
irá apareciendo de forma natural más adelante en el curso, especialmente cuando trabajemos con
grandes catálogos de libros y generación de informes.
Errores Comunes y Consejos
- Acceder a un índice fuera de rango: recuerda que los índices de un array van de
0aLength - 1. Acceder aarray[Length]es un error muy común y provoca una excepción en tiempo de ejecución. - Esperar que un array cambie de tamaño: los arrays tienen tamaño fijo. Si necesitas
añadir o quitar elementos dinámicamente, necesitarás
List<T>(Módulo 4), no un array. Créar un array de mayor tamaño y copiar los datos es posible, pero engorroso y poco habitual en la práctica. - Olvidar que las cadenas son inmutables: escribir
titulo.ToUpper();sin asignar el resultado a ninguna variable no modificatitulo; hay que hacertitulo = titulo.ToUpper();(o usar el resultado directamente donde se necesite). - Usar concatenación con
+dentro de bucles grandes: para pocos elementos no pasa nada, pero si el bucle procesa muchísimos elementos, es preferibleStringBuilder. - Confundir
Splitsin limpiar espacios: al dividir texto conSplit, cada fragmento puede llevar espacios sobrantes; conviene aplicarTrim()a cada uno, como hicimos en el ejemplo de importación de datos. - Consejo: cuando trabajes con texto que combine variables, prioriza siempre la
interpolación (
$"...") sobre la concatenación con+: el código resultante es mucho más legible y menos propenso a errores.
Ejercicios
-
Declara un array de tipo
string[]con al menos 5 títulos de libros de BiblioTech. Recórrelo conforeachy muestra cada título en una línea. Después, recórrelo con un bucleformostrando cada título numerado, empezando en 1 (por ejemplo:1. Cien anos de soledad). -
Dado el array de títulos del ejercicio anterior, escribe código que recorra el array y muestre solo los títulos que contengan la letra
"a"(usando el métodoContains, y convirtiendo el título a minúsculas conToLower()antes de comparar, para que la búsqueda no distinga mayúsculas de minúsculas). -
Usando
StringBuilder, construye un informe de texto con todos los títulos del array del ejercicio 1, con el formato:=== Catalogo BiblioTech === 1) <titulo 1> 2) <titulo 2> ...(Pista: puedes combinar un bucle
forconStringBuilder.AppendLinee interpolación de cadenas para construir cada línea numerada).
Soluciones
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph", "Pedro Paramo" };
// Recorrido con foreach
foreach (string titulo in titulosLibros)
{
Console.WriteLine(titulo);
}
Console.WriteLine("---");
// Recorrido con for, numerado desde 1
for (int i = 0; i < titulosLibros.Length; i++)
{
Console.WriteLine($"{i + 1}. {titulosLibros[i]}");
}
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph", "Pedro Paramo" };
foreach (string titulo in titulosLibros)
{
if (titulo.ToLower().Contains("a"))
{
Console.WriteLine(titulo);
}
}
Todos los títulos del ejemplo contienen la letra "a" en algún punto (mayúscula o
minúscula), por lo que el resultado mostraría los cinco; el ejercicio sirve para
practicar la combinación de ToLower() y Contains(), no tanto para obtener un
subconjunto reducido con estos datos concretos. Puedes probar con otros títulos que no
contengan la letra para comprobar que sí se filtran correctamente.
using System.Text;
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph", "Pedro Paramo" };
StringBuilder informe = new StringBuilder();
informe.AppendLine("=== Catalogo BiblioTech ===");
for (int i = 0; i < titulosLibros.Length; i++)
{
informe.AppendLine($"{i + 1}) {titulosLibros[i]}");
}
Console.WriteLine(informe.ToString());
Resultado esperado:
=== Catalogo BiblioTech ===
1) Cien anos de soledad
2) Rayuela
3) Ficciones
4) El Aleph
5) Pedro Paramo
Conclusión
En esta lección has aprendido a trabajar con arrays de una y varias dimensiones, a
recorrerlos con foreach y for, y has visto por qué List<T> (que estudiaremos en el
Módulo 4) resuelve la limitación del tamaño fijo de los arrays. También has profundizado en la
clase string: su inmutabilidad, la concatenación, la interpolación $"", sus métodos más
habituales (Split, Trim, Contains, Substring, ToUpper/ToLower) y el uso de
StringBuilder para concatenar texto de forma eficiente dentro de bucles.
Con esto se cierra el Módulo 1: Introducción a C#. Ya sabes instalar y configurar tu
entorno, escribir y ejecutar programas de consola, aplicar correctamente la sintaxis del
lenguaje, declarar variables de distintos tipos y trabajar con arrays y cadenas de texto —todo
ello aplicado, paso a paso, al proyecto BiblioTech. En el Módulo 2: Estructuras de Control
aprenderás a tomar decisiones en tu código con sentencias condicionales, a repetir acciones
con bucles, a organizar múltiples casos con switch, y a manejar errores de forma robusta con
excepciones: piezas imprescindibles para que BiblioTech empiece a comportarse como una
aplicación real, capaz de reaccionar a distintas situaciones y datos.
Curso de Programación en C#
Módulo 1: Introducción a C#
- Introducción a C#
- Configuración del Entorno de Desarrollo
- Programa Hola Mundo
- Sintaxis y Estructura Básica
- Variables y Tipos de Datos
- Arrays y Cadenas de Texto
Módulo 2: Estructuras de Control
Módulo 3: Programación Orientada a Objetos
- Clases y Objetos
- Métodos
- Constructores y Destructores
- Herencia
- Polimorfismo
- Encapsulamiento
- Abstracción
- Structs y Records: Tipos por Valor y por Referencia
Módulo 4: Conceptos Avanzados de C#
- Interfaces
- Delegados y Eventos
- Pattern Matching y Características Modernas de C#
- Genéricos
- Colecciones
- LINQ (Consulta Integrada en el Lenguaje)
- Programación Asíncrona
Módulo 5: Trabajando con Datos
- Entrada/Salida de Archivos
- Serialización
- Conectividad con Bases de Datos
- Entity Framework
- Trabajo con JSON y Consumo de APIs REST
Módulo 6: Temas Avanzados
- Reflexión
- Atributos
- Programación Dinámica
- Gestión de Memoria y Recolección de Basura
- Multihilo y Programación Paralela
Módulo 7: Construcción de Aplicaciones
- Formularios de Windows
- WPF (Windows Presentation Foundation)
- ASP.NET Core
- Blazor
- Xamarin y .NET MAUI
Módulo 8: Mejores Prácticas y Patrones de Diseño
- Estándares de Codificación y Mejores Prácticas
- Patrones de Diseño
- Inyección de Dependencias e Inversión de Control
- Pruebas Unitarias
- Revisión y Refactorización de Código
