CSharp
Tutorial CSharp: Estructuras de control condicional
Aprende las estructuras if-else, switch tradicional y switch expressions en C# para controlar el flujo de tu código con ejemplos prácticos.
Aprende CSharp y certifícateIf-else y operador ternario
Las estructuras de control condicional son fundamentales en cualquier lenguaje de programación, ya que permiten que nuestro código tome decisiones basadas en condiciones. En C#, la estructura más básica para implementar decisiones es el if-else
.
Estructura if-else
La estructura if-else
evalúa una condición y ejecuta un bloque de código si la condición es verdadera, o ejecuta otro bloque si es falsa. Su sintaxis básica es:
if (condición)
{
// Código que se ejecuta si la condición es verdadera
}
else
{
// Código que se ejecuta si la condición es falsa
}
Veamos un ejemplo sencillo:
int edad = 18;
if (edad >= 18)
{
Console.WriteLine("Eres mayor de edad");
}
else
{
Console.WriteLine("Eres menor de edad");
}
En este ejemplo, si la variable edad
es mayor o igual a 18, se mostrará "Eres mayor de edad"; de lo contrario, se mostrará "Eres menor de edad".
Uso de if sin else
También podemos usar if
sin la parte else
cuando solo queremos ejecutar código cuando se cumple una condición:
int temperatura = 30;
if (temperatura > 25)
{
Console.WriteLine("Hace calor hoy");
}
// El programa continúa aquí independientemente de la temperatura
Múltiples condiciones con else if
Cuando necesitamos evaluar múltiples condiciones en secuencia, podemos usar la estructura else if
:
int puntuacion = 85;
if (puntuacion >= 90)
{
Console.WriteLine("Sobresaliente");
}
else if (puntuacion >= 70)
{
Console.WriteLine("Notable");
}
else if (puntuacion >= 60)
{
Console.WriteLine("Bien");
}
else if (puntuacion >= 50)
{
Console.WriteLine("Suficiente");
}
else
{
Console.WriteLine("Insuficiente");
}
En este ejemplo, C# evalúa cada condición en orden. En cuanto encuentra una condición verdadera, ejecuta el bloque correspondiente y salta el resto de las condiciones.
Condiciones anidadas
También podemos anidar estructuras if-else dentro de otras:
bool esDiaLaboral = true;
bool esVacaciones = false;
if (esDiaLaboral)
{
if (esVacaciones)
{
Console.WriteLine("Es día laboral pero estás de vacaciones");
}
else
{
Console.WriteLine("Es día laboral y no estás de vacaciones");
}
}
else
{
Console.WriteLine("No es día laboral");
}
Sin embargo, es recomendable evitar demasiados niveles de anidación, ya que pueden hacer que el código sea difícil de leer y mantener.
Operadores lógicos en condiciones
Podemos combinar múltiples condiciones usando operadores lógicos:
&&
(AND): Verdadero si ambas condiciones son verdaderas||
(OR): Verdadero si al menos una condición es verdadera!
(NOT): Invierte el valor de la condición
int edad = 25;
bool tieneLicencia = true;
if (edad >= 18 && tieneLicencia)
{
Console.WriteLine("Puede conducir");
}
else if (edad >= 18 && !tieneLicencia)
{
Console.WriteLine("Tiene edad pero necesita licencia");
}
else
{
Console.WriteLine("No puede conducir");
}
Operador ternario
El operador ternario es una forma concisa de escribir una estructura if-else simple. Su sintaxis es:
resultado = condición ? valorSiVerdadero : valorSiFalso;
Este operador evalúa la condición y devuelve el primer valor si es verdadera, o el segundo valor si es falsa.
Veamos el ejemplo de la edad reescrito con el operador ternario:
int edad = 18;
string mensaje = edad >= 18 ? "Eres mayor de edad" : "Eres menor de edad";
Console.WriteLine(mensaje);
El operador ternario es especialmente útil para asignaciones condicionales simples. Hace que el código sea más compacto, pero puede volverse difícil de leer si se anida o se usa con expresiones complejas.
Ejemplos prácticos
Veamos algunos ejemplos prácticos de uso de if-else y el operador ternario:
Ejemplo 1: Verificar si un número es par o impar
int numero = 7;
if (numero % 2 == 0)
{
Console.WriteLine($"{numero} es par");
}
else
{
Console.WriteLine($"{numero} es impar");
}
// Usando operador ternario
string resultado = numero % 2 == 0 ? "par" : "impar";
Console.WriteLine($"{numero} es {resultado}");
Ejemplo 2: Calcular descuento según el monto de compra
decimal montoCompra = 120.50m;
decimal descuento;
if (montoCompra >= 100)
{
descuento = montoCompra * 0.1m; // 10% de descuento
}
else if (montoCompra >= 50)
{
descuento = montoCompra * 0.05m; // 5% de descuento
}
else
{
descuento = 0;
}
Console.WriteLine($"Monto de compra: {montoCompra:C}");
Console.WriteLine($"Descuento: {descuento:C}");
Console.WriteLine($"Total a pagar: {montoCompra - descuento:C}");
Ejemplo 3: Operador ternario en asignación
int puntos = 85;
char calificacion = puntos >= 90 ? 'A' : puntos >= 80 ? 'B' : puntos >= 70 ? 'C' : puntos >= 60 ? 'D' : 'F';
Console.WriteLine($"Puntos: {puntos}, Calificación: {calificacion}");
Este último ejemplo muestra cómo se pueden anidar operadores ternarios, aunque hay que tener cuidado con la legibilidad. En casos complejos como este, a menudo es más claro usar una estructura if-else.
Cuándo usar cada opción
Usa
if-else
cuando:La lógica condicional es compleja
Necesitas ejecutar múltiples líneas de código en cada caso
Tienes más de dos posibles caminos de ejecución
Usa el
operador ternario
cuando:La condición es simple
Solo necesitas asignar un valor basado en una condición
Quieres hacer el código más conciso
El dominio de estas estructuras condicionales es esencial para crear programas que puedan tomar decisiones basadas en diferentes situaciones y datos.
Switch tradicional
La estructura switch
en C# proporciona una forma elegante de evaluar una expresión contra múltiples valores posibles. A diferencia de las cadenas de if-else
, el switch
está optimizado para comparar una única variable o expresión contra varios casos constantes.
Sintaxis básica
La estructura básica de un switch
en C# es:
switch (expresión)
{
case valor1:
// Código a ejecutar si expresión == valor1
break;
case valor2:
// Código a ejecutar si expresión == valor2
break;
// Más casos...
default:
// Código a ejecutar si ningún caso coincide
break;
}
El switch
evalúa la expresión una sola vez y luego compara su valor con cada caso. Cuando encuentra una coincidencia, ejecuta el código asociado hasta encontrar un break
o el final del bloque switch
.
Ejemplo básico
Veamos un ejemplo sencillo que muestra un mensaje según el día de la semana:
int diaSemana = 3;
switch (diaSemana)
{
case 1:
Console.WriteLine("Lunes");
break;
case 2:
Console.WriteLine("Martes");
break;
case 3:
Console.WriteLine("Miércoles");
break;
case 4:
Console.WriteLine("Jueves");
break;
case 5:
Console.WriteLine("Viernes");
break;
case 6:
Console.WriteLine("Sábado");
break;
case 7:
Console.WriteLine("Domingo");
break;
default:
Console.WriteLine("Día no válido");
break;
}
En este ejemplo, como diaSemana
es 3, se mostrará "Miércoles" en la consola.
La importancia del break
La palabra clave break
es crucial en el switch
tradicional. Cuando se ejecuta un break
, el control sale inmediatamente del bloque switch
. Si omitimos el break
, el código continuará ejecutándose en los casos siguientes, independientemente de si coinciden o no. Esto se conoce como fall-through (caída en cascada).
int opcion = 2;
switch (opcion)
{
case 1:
Console.WriteLine("Opción 1 seleccionada");
// Sin break, continúa al siguiente caso
case 2:
Console.WriteLine("Opción 2 seleccionada");
break;
case 3:
Console.WriteLine("Opción 3 seleccionada");
break;
}
En este ejemplo, si opcion
es 2, solo se mostrará "Opción 2 seleccionada". Pero si opcion
es 1, se mostrarán tanto "Opción 1 seleccionada" como "Opción 2 seleccionada", porque falta el break
después del primer caso.
Casos múltiples
Podemos agrupar varios casos para que ejecuten el mismo código:
char calificacion = 'B';
switch (calificacion)
{
case 'A':
Console.WriteLine("Excelente");
break;
case 'B':
case 'C':
Console.WriteLine("Bien hecho");
break;
case 'D':
Console.WriteLine("Aprobado");
break;
case 'F':
Console.WriteLine("Reprobado");
break;
default:
Console.WriteLine("Calificación no válida");
break;
}
En este ejemplo, tanto 'B' como 'C' mostrarán "Bien hecho".
El caso default
El caso default
es opcional pero recomendado. Se ejecuta cuando ninguno de los otros casos coincide con la expresión evaluada:
string fruta = "Mango";
switch (fruta)
{
case "Manzana":
Console.WriteLine("Es una manzana");
break;
case "Banana":
Console.WriteLine("Es una banana");
break;
case "Naranja":
Console.WriteLine("Es una naranja");
break;
default:
Console.WriteLine($"No reconozco la fruta: {fruta}");
break;
}
Como "Mango" no coincide con ningún caso, se ejecutará el código del default
.
Tipos de datos compatibles
El switch
tradicional en C# puede trabajar con los siguientes tipos de datos:
- Tipos integrales (
int
,long
,byte
, etc.) char
string
enum
- Tipos nullable de los anteriores
enum EstadoPedido { Recibido, Procesando, Enviado, Entregado, Cancelado }
EstadoPedido estado = EstadoPedido.Enviado;
switch (estado)
{
case EstadoPedido.Recibido:
Console.WriteLine("Pedido recibido");
break;
case EstadoPedido.Procesando:
Console.WriteLine("Pedido en procesamiento");
break;
case EstadoPedido.Enviado:
Console.WriteLine("Pedido enviado");
break;
case EstadoPedido.Entregado:
Console.WriteLine("Pedido entregado");
break;
case EstadoPedido.Cancelado:
Console.WriteLine("Pedido cancelado");
break;
}
Los enum
son especialmente útiles con switch
porque proporcionan un conjunto finito de valores constantes.
Uso de variables en casos
En el switch
tradicional, los casos deben ser constantes conocidas en tiempo de compilación. No podemos usar variables o expresiones que se evalúen en tiempo de ejecución:
int valor = 5;
int casoA = 5;
switch (valor)
{
case 1 + 4: // Válido: expresión constante
Console.WriteLine("Caso 5");
break;
// case casoA: // Error: no es una constante
// Console.WriteLine("Caso variable");
// break;
default:
Console.WriteLine("Otro caso");
break;
}
Comparación con if-else
Veamos un ejemplo comparando switch
con su equivalente en if-else
:
// Usando switch
int mes = 4;
string estacion;
switch (mes)
{
case 12:
case 1:
case 2:
estacion = "Invierno";
break;
case 3:
case 4:
case 5:
estacion = "Primavera";
break;
case 6:
case 7:
case 8:
estacion = "Verano";
break;
case 9:
case 10:
case 11:
estacion = "Otoño";
break;
default:
estacion = "Mes no válido";
break;
}
// Equivalente usando if-else
if (mes == 12 || mes == 1 || mes == 2)
{
estacion = "Invierno";
}
else if (mes == 3 || mes == 4 || mes == 5)
{
estacion = "Primavera";
}
else if (mes == 6 || mes == 7 || mes == 8)
{
estacion = "Verano";
}
else if (mes == 9 || mes == 10 || mes == 11)
{
estacion = "Otoño";
}
else
{
estacion = "Mes no válido";
}
Como puedes ver, el switch
hace que el código sea más legible cuando comparamos una sola variable contra múltiples valores constantes.
Cuándo usar switch tradicional
El switch
tradicional es ideal cuando:
- Comparas una sola variable contra múltiples valores constantes
- Tienes muchas condiciones mutuamente excluyentes
- Necesitas agrupar varios valores para un mismo comportamiento
- Trabajas con enumeraciones (
enum
)
Sin embargo, tiene limitaciones:
- Solo puede evaluar igualdad (no puede usar operadores como
>
,<
, etc.) - Los casos deben ser constantes
- No puede evaluar tipos o patrones complejos (para eso existe el switch de patrones en versiones más recientes de C#)
El switch
tradicional es una herramienta fundamental en C# que, cuando se usa apropiadamente, puede hacer que tu código sea más limpio y fácil de mantener que largas cadenas de if-else
.
Switch expressions (C# 8+)
Las switch expressions son una característica moderna introducida en C# 8 que simplifica la sintaxis de las estructuras switch tradicionales. Esta nueva forma de escribir expresiones switch hace que el código sea más conciso y legible, especialmente cuando se utiliza para asignar valores basados en condiciones.
Sintaxis básica
A diferencia del switch tradicional que es una declaración (statement), una switch expression es una expresión que devuelve un valor. Su sintaxis básica es:
resultado = expresión switch
{
patrón1 => valor1,
patrón2 => valor2,
_ => valorPorDefecto
};
Observa las diferencias clave:
- Usa el operador
=>
(lambda) en lugar de dos puntos y break - Utiliza llaves
{}
en lugar de bloques de código - Termina cada caso con coma
,
- Usa
_
como caso por defecto (equivalente adefault
) - La expresión va antes de la palabra clave
switch
Ejemplo básico
Veamos cómo se ve un ejemplo simple usando switch expressions:
int diaSemana = 3;
string nombreDia = diaSemana switch
{
1 => "Lunes",
2 => "Martes",
3 => "Miércoles",
4 => "Jueves",
5 => "Viernes",
6 => "Sábado",
7 => "Domingo",
_ => "Día no válido"
};
Console.WriteLine(nombreDia); // Imprime: Miércoles
Este código es mucho más compacto que su equivalente con switch tradicional, y el propósito (asignar un valor basado en una condición) queda más claro.
Agrupación de casos
Al igual que en el switch tradicional, podemos agrupar varios casos, pero la sintaxis es diferente:
int mes = 4;
string estacion = mes switch
{
12 or 1 or 2 => "Invierno",
3 or 4 or 5 => "Primavera",
6 or 7 or 8 => "Verano",
9 or 10 or 11 => "Otoño",
_ => "Mes no válido"
};
Console.WriteLine($"Estamos en {estacion}"); // Imprime: Estamos en Primavera
Observa el uso del operador or
para combinar múltiples valores en un solo caso, lo que hace que el código sea aún más legible.
Coincidencia de patrones
Una de las ventajas más potentes de las switch expressions es la capacidad de hacer coincidencia de patrones (pattern matching). Esto permite evaluar no solo valores simples, sino también tipos, rangos y propiedades:
Coincidencia de tipos
object valor = "Hola mundo";
string mensaje = valor switch
{
string s => $"Es una cadena de {s.Length} caracteres",
int i => $"Es un entero: {i}",
double d => $"Es un número decimal: {d}",
_ => "Es otro tipo de objeto"
};
Console.WriteLine(mensaje); // Imprime: Es una cadena de 11 caracteres
Coincidencia de rangos
int temperatura = 25;
string clima = temperatura switch
{
< 0 => "Congelado",
>= 0 and < 10 => "Muy frío",
>= 10 and < 20 => "Fresco",
>= 20 and < 30 => "Agradable",
>= 30 => "Caluroso",
_ => "Temperatura no válida"
};
Console.WriteLine($"El clima está {clima}"); // Imprime: El clima está Agradable
Observa cómo usamos operadores de comparación (<
, >=
) y el operador and
para definir rangos de valores.
Deconstrucción y tuplas
Las switch expressions son especialmente útiles cuando trabajamos con tuplas, permitiendo evaluar múltiples valores a la vez:
(int Temperatura, bool EsSoleado) clima = (23, true);
string recomendacion = clima switch
{
(> 20, true) => "Usa protector solar",
(> 20, false) => "Buen día, pero nublado",
(< 10, true) => "Frío pero soleado",
(< 10, false) => "Quédate en casa, hace frío",
_ => "Clima normal"
};
Console.WriteLine(recomendacion); // Imprime: Usa protector solar
Propiedades y patrones posicionales
También podemos hacer coincidir propiedades específicas de objetos:
var punto = (X: 5, Y: -2);
string cuadrante = punto switch
{
{ X: > 0, Y: > 0 } => "Primer cuadrante",
{ X: < 0, Y: > 0 } => "Segundo cuadrante",
{ X: < 0, Y: < 0 } => "Tercer cuadrante",
{ X: > 0, Y: < 0 } => "Cuarto cuadrante",
{ X: 0, Y: 0 } => "Origen",
_ => "En un eje"
};
Console.WriteLine($"El punto está en el {cuadrante}"); // Imprime: El punto está en el Cuarto cuadrante
Cuándo usar switch expressions
Las switch expressions son ideales cuando:
- Necesitas asignar valores basados en condiciones
- Quieres un código más conciso y expresivo
- Trabajas con patrones complejos o múltiples condiciones
- Evalúas tuplas o propiedades de objetos
Comparación con switch tradicional y operador ternario
Veamos un ejemplo comparando las tres formas de escribir el mismo código:
char calificacion = 'B';
string mensaje;
// Usando switch tradicional
switch (calificacion)
{
case 'A':
mensaje = "Excelente";
break;
case 'B':
case 'C':
mensaje = "Bien hecho";
break;
case 'D':
mensaje = "Aprobado";
break;
case 'F':
mensaje = "Reprobado";
break;
default:
mensaje = "Calificación no válida";
break;
}
// Usando switch expression
mensaje = calificacion switch
{
'A' => "Excelente",
'B' or 'C' => "Bien hecho",
'D' => "Aprobado",
'F' => "Reprobado",
_ => "Calificación no válida"
};
// Usando operador ternario (para casos simples)
mensaje = calificacion == 'A' ? "Excelente" :
calificacion == 'B' || calificacion == 'C' ? "Bien hecho" :
calificacion == 'D' ? "Aprobado" :
calificacion == 'F' ? "Reprobado" :
"Calificación no válida";
Como puedes ver, la switch expression ofrece un buen equilibrio entre la concisión del operador ternario y la claridad del switch tradicional.
Ejemplo práctico: Calculadora simple
Veamos un ejemplo práctico de una calculadora simple usando switch expressions:
char operador = '+';
int a = 10, b = 5;
int resultado = operador switch
{
'+' => a + b,
'-' => a - b,
'*' => a * b,
'/' => b != 0 ? a / b : throw new DivideByZeroException("No se puede dividir por cero"),
_ => throw new ArgumentException($"Operador no soportado: {operador}")
};
Console.WriteLine($"{a} {operador} {b} = {resultado}"); // Imprime: 10 + 5 = 15
Observa cómo podemos incluso lanzar excepciones dentro de una switch expression, lo que la hace muy flexible.
Limitaciones
Aunque las switch expressions son muy potentes, tienen algunas limitaciones:
- No pueden contener bloques de código complejos (solo expresiones)
- No pueden tener efectos secundarios complejos (aunque se pueden usar operadores condicionales y lanzar excepciones)
- Requieren C# 8.0 o superior, por lo que no están disponibles en proyectos que apuntan a versiones anteriores del lenguaje
A pesar de estas limitaciones, las switch expressions representan una mejora significativa en la legibilidad y expresividad del código C#, especialmente para casos de asignación condicional que antes requerían estructuras más verbosas.
Ejercicios de esta lección Estructuras de control condicional
Evalúa tus conocimientos de esta lección Estructuras de control condicional con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
CRUD en C# de modelo Customer sobre una lista
Arrays y listas
Objetos
Excepciones
Eventos
Lambdas
Diccionarios en C#
Variables y constantes
Tipos de datos
Herencia
Operadores
Uso de consultas LINQ
Clases y encapsulación
Uso de consultas LINQ
Excepciones
Control de flujo
Eventos
Diccionarios
Tipos de datos
Conjuntos, colas y pilas
Lambdas
Conjuntos, colas y pilas
Uso de async y await
Tareas
Constructores y destructores
Operadores
Arrays y listas
Polimorfismo
Polimorfismo
Variables y constantes
Proyecto colecciones y LINQ en C#
Clases y encapsulación
Creación de proyecto C#
Uso de async y await
Funciones
Delegados
Delegados
Constructores y destructores
Objetos
Control de flujo
Funciones
Tareas
Proyecto sintaxis en C#
Herencia C Sharp
OOP en C Sharp
Diccionarios
Introducción a C#
Todas las lecciones de CSharp
Accede a todas las lecciones de CSharp y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A C#
Introducción Y Entorno
Creación De Proyecto C#
Introducción Y Entorno
Variables Y Constantes
Sintaxis
Tipos De Datos
Sintaxis
Operadores
Sintaxis
Control De Flujo
Sintaxis
Funciones
Sintaxis
Estructuras De Control Iterativo
Sintaxis
Interpolación De Strings
Sintaxis
Estructuras De Control Condicional
Sintaxis
Manejo De Valores Nulos
Sintaxis
Clases Y Encapsulación
Programación Orientada A Objetos
Objetos
Programación Orientada A Objetos
Constructores Y Destructores
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Genéricos
Programación Orientada A Objetos
Métodos Virtuales Y Sobrecarga
Programación Orientada A Objetos
Clases Abstractas
Programación Orientada A Objetos
Interfaces
Programación Orientada A Objetos
Propiedades Y Encapsulación
Programación Orientada A Objetos
Métodos De Extensión
Programación Orientada A Objetos
Clases Y Objetos
Programación Orientada A Objetos
Clases Parciales
Programación Orientada A Objetos
Miembros Estáticos
Programación Orientada A Objetos
Tuplas Y Tipos Anónimos
Programación Orientada A Objetos
Arrays Y Listas
Colecciones Y Linq
Diccionarios
Colecciones Y Linq
Conjuntos, Colas Y Pilas
Colecciones Y Linq
Uso De Consultas Linq
Colecciones Y Linq
Linq Avanzado
Colecciones Y Linq
Colas Y Pilas
Colecciones Y Linq
Conjuntos
Colecciones Y Linq
Linq Básico
Colecciones Y Linq
Delegados Funcionales
Programación Funcional
Records
Programación Funcional
Expresiones Lambda
Programación Funcional
Linq Funcional
Programación Funcional
Fundamentos De La Programación Funcional
Programación Funcional
Pattern Matching
Programación Funcional
Testing Unitario Con Xunit
Testing
Excepciones
Excepciones
Delegados
Programación Asíncrona
Eventos
Programación Asíncrona
Lambdas
Programación Asíncrona
Uso De Async Y Await
Programación Asíncrona
Tareas
Programación Asíncrona
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender la sintaxis y uso básico de if-else y operador ternario en C#.
- Aprender a manejar múltiples condiciones y anidaciones con if, else if y else.
- Conocer la estructura y funcionamiento del switch tradicional, incluyendo casos múltiples y la importancia del break.
- Explorar las switch expressions introducidas en C# 8 para escribir código más conciso y expresivo.
- Aplicar patrones de coincidencia y trabajar con tuplas y propiedades en switch expressions para casos complejos.