99 - Excepciones en C# - try/catch


C# dispone de un mecanismo de capturar (catch) ciertos tipos de errores que solo pueden ser detectados en tiempo de ejecución del programa.

Los ejemplos más comunes que podemos nombrar de excepciones:

  • Tratar de convertir a entero un string que no contiene valores numéricos.
  • Tratar de dividir por cero.
  • Abrir un archivo de texto inexistente o que se encuentra bloqueado por otra aplicación.
  • Conectar con un servidor de bases de datos que no se encuentra activo.
  • Acceder a subíndices de vectores y matrices fuera de rango.

La captura de excepciones nos permite crear programas mucho más robustos y tolerante a fallas que ocurren en escasas situaciones, pero en caso que se presenten disponemos de un algoritmo alternativo para reaccionar a dicha situación evitando que el programa finalice su ejecución.

Veremos un ejemplo sin captura de excepciones y luego la sintaxis implementando su captura.

Problema:

Realizar la carga de un número entero por teclado e imprimir su cuadrado.

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PruebaExcepcion1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Ingrese un valor:");
            string linea = Console.ReadLine();
            var num = int.Parse(linea);
            var cuadrado = num * num;
            Console.WriteLine($"El cuadrado de {num} es {cuadrado}");
            Console.ReadKey();
        }
    }
}

Si ejecutamos el programa y el operador ingresa caracteres no numéricos en lugar de un entero se genera una excepción y el programa se detiene en forma inmediata:

C# excepciones sin capturar

El programa no ejecuta más instrucciones después de la línea 15 del método Main. Se informa el nombre de excepción generada: System.FormatException, es decir se nos informa el nombre de clase de excepción y el espacio de nombres que la contiene: System

Lo primero que podemos decir que las excepciones no son obligatorias capturarlas, pero como vemos si nuestro usuario del programa en forma frecuente se equivoca y carga caracteres no numéticos en lugar de enteros el programa se detiene y requiere que lo vuelva a ejecutar.

Podemos implementar un programa más robusto si capturamos la excepción FormatException y le informamos al usuario que debe ingresar un entero obligatoriamente.

Veamos ahora la sintaxis del mismo programa pero capturando la excepción:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PruebaExcepcion1
{
    class Program
    {
        static void Main(string[] args)
        {
            try {
                Console.Write("Ingrese un valor:");
                string linea = Console.ReadLine();
                var num = int.Parse(linea);
                var cuadrado = num * num;
                Console.WriteLine($"El cuadrado de {num} es {cuadrado}");
            }
            catch(FormatException e)
            {
                Console.Write("Debe ingresar obligatoriamente un número entero.");
            }
            Console.ReadKey();
        }
    }
}

Para atrapar las excepciones debemos encerrar en un bloque try las instrucciones que generan excepciones, en nuestro caso el método 'Parse' de la clase int:

            try {
                Console.Write("Ingrese un valor:");
                string linea = Console.ReadLine();
                var num = int.Parse(linea);
                var cuadrado = num * num;
                Console.WriteLine($"El cuadrado de {num} es {cuadrado}");
            }

Todo bloque try requiere que sea seguido por un bloque catch:

            catch(FormatException e)
            {
                Console.Write("Debe ingresar obligatoriamente un número entero.");
            }

Luego de la palabra clave catch se indica entre paréntesis el nombre de un parámetro cualquiera (en nuestro caso lo llamamos 'e') y el nombre de la excepción a capturar.

El bloque catch normalmente no se ejecuta salvo en los casos excepcionales que dentro del bloque try informa que se disparó dicha excepción.

Ahora si ejecutamos el programa y el operador ingresa una cadena no numérica en lugar de un entero nuestro programa no se detiene sino se le informa el tipo de error que cometió el usuario:

C# excepciones capturar

Cuando se dispara una excepción las instrucciones que hay luego del método que la disparó no se ejecutan:

                var cuadrado = num * num;
                Console.WriteLine($"El cuadrado de {num} es {cuadrado}");

La dos instrucciones luego de llamar al método 'Parse' no se ejecutan si dicho método eleva la excepción.

Podemos modificar ahora nuestro programa aun más para que no finalice hasta que cargue un valor entero:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PruebaExcepcion1
{
    class Program
    {
        static void Main(string[] args)
        {
            bool continua;
            do
            {
                try
                {
                    continua = false;
                    Console.Write("Ingrese un valor:");
                    string linea = Console.ReadLine();
                    var num = int.Parse(linea);
                    var cuadrado = num * num;
                    Console.WriteLine($"El cuadrado de {num} es {cuadrado}");
                }
                catch (FormatException e)
                {
                    Console.WriteLine("Debe ingresar obligatoriamente un número entero.");
                    continua = true;
                }
            } while (continua);
            Console.ReadKey();
        }

    }
}

Si ejecutamos esta variante de programa, el pedido de la carga del entero no finalizará hasta que lo ingrese en forma correcta:

C# excepciones capturar

Retornar