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ícate

If-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 a default)
  • 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.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

30 % DE DESCUENTO

Plan mensual

19.00 /mes

13.30 € /mes

Precio normal mensual: 19 €
63 % DE DESCUENTO

Plan anual

10.00 /mes

7.00 € /mes

Ahorras 144 € al año
Precio normal anual: 120 €
Aprende CSharp online

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.

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

Accede GRATIS a CSharp y certifícate

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.