Header Ads Widget

Excepciones comunes de C # y cómo solucionarlas



Si escribe software para ganarse la vida en 2018, es probable que al menos esté familiarizado con el concepto de excepciones.
Jeff Atwood una vez los llamó "el pan y la mantequilla de los lenguajes de programación modernos". Las excepciones son una construcción común y útil presente en el desarrollo de software moderno, pero a veces también pueden ser bastante confusas.
¿Qué son las excepciones, después de todo? Más específicamente, ¿cuáles son los principales tipos de excepciones de C # y cómo los usa?
La publicación de hoy responderá a las preguntas anteriores, y más. Comenzaremos con una breve definición de "excepción" y procederemos a explicar las partes compuestas de la estructura. Finalmente, haremos una descripción general de las excepciones más comunes de C # y cómo tratarlas.
Empecemos.

¿Qué es una excepción?

Una excepción es un mecanismo que puede utilizar para tratar los errores. Es así de simple. En ciertos escenarios donde, digamos, un programador de C devolvería un código de error, lo más probable es que un programador de Java o C # lance una excepción.
Una excepción representa una interrupción abrupta del flujo de ejecución. Tan pronto como se lanza una excepción, la ejecución se detiene. Si la excepción no se maneja, la aplicación se bloquea.
Pero, ¿cómo se hace eso en la práctica? ¿Cómo tirar o atrapar una excepción? ¿Qué significa todo eso?
Eso es lo que veremos en detalle en la siguiente sección.

Anatomía de las excepciones de C #

Ahora cubriremos brevemente la anatomía de una excepción de C #. Aprenderá sobre las palabras clave principales que debe usar no solo para detectar y manejar excepciones, sino también para lanzar las suyas propias. Primero en nuestra lista es la trypalabra clave y el bloque.

Tratar

La primera parte de la anatomía del manejo de excepciones es el trybloque. Se usa para tratar de ejecutar algún código que puede generar excepciones. Considere el siguiente extracto de código:
string content = string.Empty;
try
{
content = System.IO.File.ReadAllText(@"C:\file.txt");
}
El código anterior declara una variable y le asigna la cadena vacía. Entonces, tenemos el trybloque. La única línea de código dentro del trybloque usa el ReadAllTextmétodo estático de la System.IO.Fileclase. Tememos que el archivo representado por la ruta no exista, en cuyo caso se producirá una excepción. Pero por supuesto, eso no es suficiente. Nuestro código no hace nada para manejar la excepción. ¡Ni siquiera compila actualmente! Este es el mensaje del compilador:
Expected catch or finally
El mensaje es autoexplicativo. Necesitamos un bloque catcho finallyya que no tiene ningún sentido tratar de manejar una excepción y luego olvidarse de hacer la parte de manejo. Vamos a eso.

Captura

El catchbloque es lo que nos permite manejar la excepción. Ampliaremos el ejemplo anterior con más código.
Echale un vistazo:
        static void Main(string[] args)
{
string content = string.Empty;

try
{
Console.WriteLine("First message inside try block.");
Console.WriteLine("Second message inside try block.");
content = System.IO.File.ReadAllText(@"C:\file.txt");
Console.WriteLine("Third message inside try block. This shouldn't be printed.");
}
catch
{
Console.WriteLine("First message inside the catch block.");
Console.WriteLine("Second message inside the catch block.");
}

Console.WriteLine("Outside the try-catch.");
Console.ReadLine();
}
Si ejecuta el código anterior, esto es lo que debería ver:
First message inside try block.
Second message inside try block.
First message inside the catch block.
Second message inside the catch block.
Outside try-catch.
El archivo en esa ruta no existe, por lo que System.FileNotFoundExceptionse lanza un. El flujo de ejecución se interrumpe inmediatamente cuando eso sucede. Así que la línea que imprimiría "Tercer mensaje dentro del bloque try. Esto no debería ser impreso ". Nunca se ejecuta.
El flujo de ejecución es recogido por el catchbloque, que ejecuta sus dos líneas. Cuando termina, devuelve el control al método principal, que luego imprime Outside try-catch. y espera la entrada del usuario.

Finalmente

Después de aprender sobre tryy catch, finalmente estamos (sin ningún juego de palabras) listos para asimilar esta parte muy útil pero a menudo mal entendida del mecanismo de manejo de excepciones. Entonces, ¿qué es finally?
El finallybloque es una forma de asegurarse de que se va a ejecutar un determinado fragmento de código, independientemente de si se lanza una excepción o no. Considere el siguiente código:
try
{
content = System.IO.File.ReadAllText(path);
Console.WriteLine("If you're reading this, no exception was thrown.");
}
catch (System.IO.FileNotFoundException e)
{
Console.WriteLine("If you're reading this, an exception was thrown.");
Console.WriteLine("Message: " + e.Message);
}
finally
{
Console.WriteLine("This will be printed, no matter what.");
}
Sigue siendo el mismo ejemplo, pero ahora es mucho más simple. Fíjate en el finallybloque al final. Si ejecuta este código, debería ver los siguientes mensajes:
If you're reading this, an exception was thrown.
Message: Could not find file 'C:\file.txt'.
This will be printed, no matter what.
Outside the try-catch.
Ahora simulemos la existencia del archivo. Comente la línea tratando de leer el archivo y vuelva a ejecutar la aplicación. Esto es lo que deberías ver ahora:
If you're reading this, no exception was thrown.
This will be printed, no matter what.
Outside the try-catch.
Como puede ver, en el escenario más reciente, la excepción no fue lanzada, por lo que no se ejecutaron líneas en el catchbloque. Por otro lado, el finallybloque se ejecutó en ambos escenarios.

Lanzar

Cuando se trata de excepciones, no siempre las manejarás desde otros; También puedes lanzar el tuyo. Para eso, va a utilizar la throwpalabra clave, seguida de una instanciación de la clase para la excepción que desea lanzar. El siguiente código ejemplifica esto:
public ProductService(IProductRepository repository)
{
if (repository == null)
throw new ArgumentNullException();

this.repository = repository;
}

Excepciones comunes de .NET

La siguiente es una lista de excepciones comunes de .NET:

System.NullReferenceException

Esta es una de las excepciones más famosas (o más bien infames) que existen. Esta excepción se produce cuando intenta llamar a un método / propiedad / indexador / etc. en una variable que contiene una referencia nula, es decir, no apunta a ningún objeto. El siguiente código causará una excepción de referencia nula:
Person p = people.Where(x => x.SSN == verifySsn).FirstOrDefault();
string name = p.Name;
En el ejemplo anterior, filtramos una secuencia que compara la propiedad SSN en cada elemento con la verifySsnvariablevariable. Luego usamos el FirstOrDefault()método para tomar solo el primer elemento de la secuencia. Si la secuencia no produce ningún elemento, devuelve el valor predeterminado para el tipo. Dado que Persones un tipo de referencia, su valor de retorno es nulo.
En la siguiente línea, intentamos anular la referencia de la Namepropiedad en una referencia nula. ¡Auge! Excepcion de referencia nula.
Esta es una excepción que usualmente ni tiras ni atrapas. No lo lanzas porque sería inútil. Si desea comunicar a los clientes de su código que un método determinado no acepta el valor nulo como valores válidos para sus parámetros, la excepción correcta a usar es la System.ArgumentNullException.
¿Cómo “arreglas” esta excepción? En resumen, debe ser cuidadoso y diligente sobre la nulabilidad. Si está escribiendo un fragmento de código que será utilizado por terceros, incluso si esos terceros son sus compañeros de trabajo, piense muy bien si aceptar o no las referencias nulas como valores válidos.
Decida lo que decida, tome esa decisión muy clara y documéntela bien. Lo haces lanzando System.ArgumentNullException, por ejemplo, y también usando encabezados de documentación XML en tus métodos.

System.IndexOutOfRangeException

Esta excepción es similar a la anterior en el sentido de que el código de la aplicación normalmente no lo lanzaría ni lo atraparía.
¿Y por qué es eso?
Bueno, esta excepción se produce cuando intentas acceder a un elemento desde una matriz, lista o cualquier secuencia indexable utilizando un valor de índice no válido. Un ejemplo rápido:
public static void PrintUrlSufix(string url)
{
var parts = url.Split('.');
Console.WriteLine(parts[2]);
}
El código anterior aparentemente espera una URL en el formato www.acme.com . Pero ¿y si solo se pone acme.com ? Para el caso, ¿qué pasa si se Hakuna Matata ? Sí, es cierto: System.IndexOutOfBoundExceptionlo es.
¿Cómo se evita esta excepción? Nunca tomes las cosas por sentado. Nunca asuma que los datos estarán en el formato correcto. Haga su diligencia debida y revise las cosas.

System.IO.IOException

Esta excepción de C # tiene un nombre que se explica por sí mismo. Es exactamente lo que pensaría: es la excepción que se produce cuando las cosas salen mal durante las operaciones de IO. A diferencia de las dos excepciones anteriores, es posible que se encuentre atrapando o lanzando una de estas de vez en cuando.
La IOExceptionclase es en realidad el padre de algunas excepciones más específicas, a saber:
  • DirectoryNotFoundException
  • EndOfStreamException
  • FileNotFoundException
  • FileLoadException
  • PathTooLongException
La documentación para IOExceptionrecomienda que, siempre que sea posible, utilice las excepciones más específicas en lugar de la más general.

System.Net.WebException

Esta excepción está relacionada con la red. Se produce si se produce un error al acceder a la red mediante un protocolo conectable. Al manejar esta excepción, recuerde verificar la Responsepropiedad, que contendrá la respuesta devuelta por el host remoto.

System.Data.SqlClient.SqlException

Esta excepción está relacionada con la base de datos, específicamente, con SQL Server. Se lanza cuando SQL Server devuelve un error o una advertencia. La clase tiene una propiedad llamada Errors, que es una colección que contiene una o más instancias de la SqlErrorclase. Eso, a su vez, contiene información detallada sobre los errores que ocurrieron.

System.StackOverflowException

Esta excepción se produce cuando la pila de ejecución se desborda, lo que generalmente significa que la recursión salió mal. El código tiene demasiadas llamadas de método anidadas. Y aquí está la cosa: esta excepción no es detectable, al menos no desde .NET 2.0, lo que significa que prácticamente no tienes alternativas cuando se lanza esta excepción. Su proceso será terminado de forma predeterminada.
Lo que debe hacer en lugar de capturar esta excepción es escribir código que evite que suceda en primer lugar.

System.OutOfMemoryException

Esta es posiblemente una de las excepciones de C # más confusas que existen . Hay recursos en la web que hacen un gran trabajo para aclarar el problema , pero ofreceré una versión corta aquí. Lo que sucede es que esta excepción no se refiere a la memoria física disponible.
Entonces, ¿cuándo se lanza esta excepción?
¿Sabe cuándo quiere estacionar su automóvil y no puede porque otros conductores no han estacionado correctamente? Si pudiera agregar todos los espacios disponibles entre los autos estacionados, sería más que suficiente para adaptarse a su vehículo. Pero actualmente, no es posible porque no es un área contigua.
Eso es más o menos lo que sucede cuando obtienes este recuerdo. Puede haber un montón de memoria total disponible, pero no hay una parte continua para cumplir con la asignación necesaria. En la práctica, esta excepción ocurre, por ejemplo, si intenta expandir una propiedad StringBuildermás allá de su MaxCapacitypropiedad.

System.InvalidCastException

Esta excepción también tiene un nombre que se explica por sí mismo. Se lanza cuando el código no realiza una conversión de un tipo a otro porque no hay una conversión definida. El siguiente código arrojaría una excepción de este tipo:
object o = "10";
int x = (int)o;
Esta es una excepción que normalmente no atraparía. Más bien, escribirías tu código de tal manera que no suceda. Por ejemplo, el siguiente código realiza una verificación de tipo antes de intentar realizar el lanzamiento:
public override bool Equals (object obj )
{
if (!obj is Foo)
return false;

Foo other = (Foo)obj;
return this.bar == other.bar;
}
El código anterior podría simplificarse utilizando el asoperador , pero lo dejaré como un ejercicio para el lector. De todos modos, aquí está la cosa: lo que realmente deberías estar tratando de hacer es evitar el problema al no lanzar en primer lugar. Utilice los genéricos para evitar meterse en situaciones que necesitan ser lanzados.

System.InvalidOperationException

Esta excepción, como muchas otras anteriores, es una que normalmente no atraparía. En cambio, lo que debes hacer es codificar de tal manera que no suceda. Considere el siguiente ejemplo:
var numbers = new List<int> { 1, 3, 5 };
var firstGreaterThanFive = numbers.Where(x => x > 5).First();
El método de extensión First LINQ se produce cuando la secuencia no genera ningún resultado. Si sabe que la secuencia puede no producir resultados a veces, y eso está bien, debería usar FirstOrDefault en su lugar. Este método, cuando se llama en una secuencia vacía, devuelve el valor predeterminado para el tipo de secuencia en lugar de lanzar.

System.ObjectDisposedException

La última excepción de C # que cubriremos en esta publicación también cae en la categoría de "no debería manejar, corregir su código". En otras palabras, es un error del desarrollador. Esta excepción se produce cuando intenta hacer algo con un IDisposible que ya se eliminó.
Esto suele suceder cuando el desarrollador llama al Dispose, Closeu otro método similar y luego intenta acceder a un miembro del objeto.

Manejo de errores para la victoria.

El manejo de errores es un tema que a menudo se pasa por alto cuando se trata de la enseñanza del desarrollo de software. Y eso es lo más desafortunado. Sin una sólida estrategia de manejo de errores , sus aplicaciones siempre serán insatisfactorias.
Con esta publicación, esperamos haber hecho un poco para ayudar a solucionar este problema definiendo el concepto de excepción y haciendo una descripción general rápida de los principales tipos de excepciones de C #. ¿Esto es todo lo que hay para el manejo de excepciones?
De ninguna manera. Piense en esto como una oportunidad para comenzar a poner en marcha sus estudios sobre el tema y nunca dejar de aprender y practicar. ¡Y le deseo suerte en la creación de una estrategia que funcione bien para su aplicación!

Publicar un comentario

0 Comentarios