Cómo usar try catch para el manejo de excepciones es la mejor práctica

201

Mientras mantengo el código de mi colega incluso de alguien que dice ser un desarrollador senior, a menudo veo el siguiente código:

try
{
  //do something
}
catch
{
  //Do nothing
}

o a veces escriben información de registro en archivos de registro como el siguiente try catchbloque

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

Me pregunto si lo que han hecho es la mejor práctica. Me confunde porque, en mi opinión, los usuarios deben saber qué sucede con el sistema.

Por favor, dame un consejo.

Toan Nguyen
fuente
128
El fragmento n. ° 1 es inaceptable en un 99.999% de las veces.
leppie
22
Mostrar una excepción directamente al usuario nunca es una buena idea, principalmente por dos razones: 1. si se trata de usuarios habituales, se molestará al leer un mensaje de error que le dice muy pocos. 2. si (s) es, así llamado, hacker (es), puede obtener información útil. La mejor práctica, IMO, es registrar una excepción y mostrar un mensaje de error amigable.
Leri
44
@leppie Si ocurre algo inesperado (como NullReferenceo ArgumentNullque no forma parte del flujo de la aplicación), significa que hay un error que debe corregirse, por lo que registrarlo ayudará a depurar su código mucho más rápido.
Leri
14
El uso de un bloque try-catch para ocultar una excepción es generalmente el resultado de una programación diferida. Es un acceso directo que a menudo se usa en lugar de escribir código de validación para probar entradas. Muy ocasionalmente, hay ocasiones en que puede surgir una excepción que no afecta el funcionamiento de su código, y ocultarlo de esta manera podría estar bien. Sin embargo, esto es bastante raro.
Corey
12
@Toan, bueno, si se trata de un trabajo por lotes, estoy capturando en el nivel superior (Principal) para iniciar sesión, y luego vuelvo a lanzar para activar una alarma de que el trabajo terminó anormalmente. Si se trata de una aplicación web, dejo que la excepción aparezca en un controlador global, inicie sesión y luego redirija al usuario a una pantalla de error. El escenario de su caso de uso dicta lo que debe hacer con esa excepción después de haberlo registrado o manejado.
Anthony Pegram

Respuestas:

300

Mi estrategia de manejo de excepciones es:

  • Para capturar todas las excepciones no controladas conectándose a la Application.ThreadException event, luego decida:

    • Para una aplicación de IU: para mostrarla al usuario con un mensaje de disculpa (winforms)
    • Para un servicio o una aplicación de consola: regístrelo en un archivo (servicio o consola)

Luego siempre adjunto cada pieza de código que se ejecuta externamente en try/catch:

  • Todos los eventos activados por la infraestructura de Winforms (Load, Click, SelectedChanged ...)
  • Todos los eventos activados por componentes de terceros.

Luego lo adjunto en 'try / catch'

  • Es posible que todas las operaciones que conozco no funcionen todo el tiempo (operaciones de E / S, cálculos con una división de cero potencial ...). En tal caso, lanzo un nuevo ApplicationException("custom message", innerException)para hacer un seguimiento de lo que realmente sucedió

Además, hago todo lo posible para ordenar las excepciones correctamente . Hay excepciones que:

  • debe mostrarse al usuario de inmediato
  • requieren un procesamiento adicional para armar las cosas cuando ocurren para evitar problemas en cascada (es decir: poner .EndUpdate en la finallysección durante un TreeViewllenado)
  • Al usuario no le importa, pero es importante saber qué sucedió. Así que siempre los registro:

    • En el registro de eventos
    • o en un archivo .log en el disco

Es una buena práctica diseñar algunos métodos estáticos para manejar excepciones en los controladores de errores de nivel superior de la aplicación.

También me obligo a intentar:

  • Recuerde que TODAS las excepciones aparecen en el nivel superior . No es necesario poner controladores de excepciones en todas partes.
  • Las funciones llamadas reutilizables o profundas no necesitan mostrar o registrar excepciones: se activan automáticamente o se vuelven a generar con algunos mensajes personalizados en mis controladores de excepciones.

Así que finalmente :

Malo:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

Inútil:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

Intentar finalmente sin una trampa es perfectamente válido:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

Lo que hago en el nivel superior:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

Lo que hago en algunas funciones llamadas:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

Hay mucho que ver con el manejo de excepciones (Excepciones personalizadas), pero esas reglas que trato de tener en cuenta son suficientes para las aplicaciones simples que hago.

Aquí hay un ejemplo de métodos de extensiones para manejar excepciones atrapadas de una manera cómoda. Se implementan de una manera que se pueden encadenar, y es muy fácil agregar su propio procesamiento de excepciones capturadas.

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}
Larry
fuente
98
catch(Exception ex) { throw ex; }en C # es peor que redundante (independientemente del tipo de excepción que esté detectando). Para volver a lanzar, use throw;. Con el primero, la excepción parecerá que se originó a partir de su, throw exmientras que con el último, se originará correctamente a partir de la throwdeclaración original .
un CVn
2
¿Por qué enganchas el Application.ThreadExceptionevento y envuelves cada excepción con un catch(Exception ex) {ex.Log(ex);}. Probablemente estaría de acuerdo en que la primera es una práctica excelente, pero la segunda agrega el riesgo de duplicar sus registros de errores y oculta que ocurrió la excepción. También throw exes muy muy malo.
Keith
1
Entendí sobre catch (Exception ex) {throw ex; } ser inútil. Así que supongo que "redundante" no es la mejor palabra para decir "No hagas esto". Es por eso que cambié un poco la publicación para afirmar mejor que los dos primeros ejemplos de try catch deben evitarse.
Larry
3
Excelente y constructiva respuesta, sobre todo disfruté la frase Only air :) Y gracias por el Application.ThreadExceptionevento, no estaba al tanto de eso, muy útil.
Mahdi Tahsildari
61

La mejor práctica es que el manejo de excepciones nunca debe ocultar problemas . Esto significa que los try-catchbloques deberían ser extremadamente raros.

Hay 3 circunstancias en las que usar un try-catchtiene sentido.

  1. Trate siempre con las excepciones conocidas lo más bajo posible. Sin embargo, si espera una excepción, por lo general, es una mejor práctica probarla primero. Por ejemplo, las excepciones de análisis, formato y aritmética casi siempre se manejan mejor mediante verificaciones lógicas primero, en lugar de una específica try-catch.

  2. Si necesita hacer algo en una excepción (por ejemplo, iniciar sesión o revertir una transacción), vuelva a lanzar la excepción.

  3. Siempre trate con excepciones desconocidas tan alto como sea posible: el único código que debería consumir una excepción y no volver a lanzarlo debería ser la interfaz de usuario o la API pública.

Suponga que se está conectando a una API remota, aquí sabe que espera ciertos errores (y tiene que hacerlo en esas circunstancias), así que este es el caso 1:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

Tenga en cuenta que no se detectan otras excepciones, ya que no se esperan.

Ahora suponga que está intentando guardar algo en la base de datos. Tenemos que revertirlo si falla, por lo que tenemos el caso 2:

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

Tenga en cuenta que volvemos a lanzar la excepción: el código más arriba aún necesita saber que algo ha fallado.

Finalmente tenemos la interfaz de usuario: aquí no queremos tener excepciones completamente no controladas, pero tampoco queremos ocultarlas. Aquí tenemos un ejemplo del caso 3:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

Sin embargo, la mayoría de los marcos de API o UI tienen formas genéricas de hacer el caso 3. Por ejemplo, ASP.Net tiene una pantalla de error amarilla que vuelca los detalles de la excepción, pero que puede reemplazarse con un mensaje más genérico en el entorno de producción. Seguirlas es una práctica recomendada porque le ahorra mucho código, pero también porque el registro de errores y la visualización deben ser decisiones de configuración en lugar de codificadas.

Todo esto significa que el caso 1 (excepciones conocidas) y el caso 3 (manejo único de la IU) tienen mejores patrones (evite el error esperado o el manejo manual de errores en la IU).

Incluso el caso 2 puede ser reemplazado por mejores patrones, por ejemplo, los ámbitos de transacción ( usingbloques que deshacen cualquier transacción que no se haya comprometido durante el bloque) dificultan que los desarrolladores obtengan el patrón de mejores prácticas incorrecto.

Por ejemplo, suponga que tiene una aplicación ASP.Net a gran escala. El registro de errores puede realizarse a través de ELMAH , la visualización de errores puede ser un YSoD informativo localmente y un buen mensaje localizado en producción. Las conexiones a la base de datos pueden realizarse mediante ámbitos y usingbloques de transacciones . No necesitas un solo try-catchbloque.

TL; DR: La mejor práctica es no utilizar try-catchbloques en absoluto.

Keith
fuente
44
@Jorj, deberías leer la publicación completa, y si aún no estás de acuerdo, tal vez sería más constructivo contrarrestar uno de mis argumentos de apoyo en lugar de simplemente decir que no te gusta mi conclusión. Casi siempre hay un patrón mejor que try-catch: puede (muy ocasionalmente) ser útil y no estoy discutiendo que nunca debas usarlos, pero el 99% de las veces hay una mejor manera.
Keith
La mejor respuesta con diferencia: casi todos los tipos de desarrollo .net tienen un MANEJADOR de algún tipo que se adapta mucho mejor a las excepciones a nivel global, lo que hace que sea mucho más fácil manejarlas de manera coherente y que sea mucho más fácil simplemente dejar que sople en desarrollo (¿por qué alguien querría cavar a través de un archivo de registro para un seguimiento de la pila?) @Kieth, lideraría con su TLDR y agregaría algunos ejemplos de los controladores globales (es decir, ThreadException, Application_Error, etc.). Por
supuesto
34

Una excepción es un error de bloqueo .

En primer lugar, la mejor práctica debería ser no lanzar excepciones para ningún tipo de error, a menos que sea un error de bloqueo .

Si el error está bloqueando , arroje la excepción. Una vez que se lanza la excepción, no hay necesidad de ocultarla porque es excepcional; informe al usuario al respecto (debe volver a formatear toda la excepción a algo útil para el usuario en la interfaz de usuario).

Su trabajo como desarrollador de software es tratar de evitar un caso excepcional en el que algún parámetro o situación de tiempo de ejecución pueda terminar en una excepción. Es decir, las excepciones no deben silenciarse, pero deben evitarse .

Por ejemplo, si sabe que alguna entrada entera podría tener un formato no válido, use en int.TryParselugar de int.Parse. Hay muchos casos en los que puedes hacer esto en lugar de solo decir "si falla, simplemente lanza una excepción".

Lanzar excepciones es costoso.

Si, después de todo, se lanza una excepción, en lugar de escribir la excepción en el registro una vez que se ha lanzado, una de las mejores prácticas es detectarla en un controlador de excepciones de primera oportunidad . Por ejemplo:

  • ASP.NET: Global.asax Application_Error
  • Otros: evento AppDomain.FirstChanceException .

Mi postura es que los intentos / capturas locales son más adecuados para manejar casos especiales en los que puede traducir una excepción a otra, o cuando desea "silenciarla" por un caso muy, muy, muy, muy especial (un error de biblioteca arrojando una excepción no relacionada que necesita silenciar para solucionar todo el error).

Para el resto de los casos:

  • Intenta evitar excepciones.
  • Si esto no es posible: manejadores de excepciones de primera oportunidad.
  • O use un aspecto PostSharp (AOP).

Respondiendo a @thewhiteambit por algún comentario ...

@thewhiteambit dijo:

Las excepciones no son errores fatales, ¡son excepciones! A veces ni siquiera son errores, pero considerarlos errores fatales es una comprensión completamente falsa de lo que son las excepciones.

En primer lugar, ¿cómo una excepción no puede ser ni siquiera un error?

  • Sin conexión de base de datos => excepción.
  • Formato de cadena no válido para analizar a algún tipo => excepción
  • Intentando analizar JSON y aunque la entrada no es realmente JSON => excepción
  • Argumento nullmientras se esperaba el objeto => excepción
  • Algunas bibliotecas tienen un error => produce una excepción inesperada
  • Hay una conexión de socket y se desconecta. Luego intenta enviar un mensaje => excepción
  • ...

Podríamos enumerar 1k casos de cuando se lanza una excepción, y después de todo, cualquiera de los casos posibles será un error .

Una excepción es un error, porque al final del día es un objeto que recopila información de diagnóstico: tiene un mensaje y ocurre cuando algo sale mal.

Nadie lanzaría una excepción cuando no hay un caso excepcional. Las excepciones deberían ser errores de bloqueo porque una vez que se lanzan, si no intenta caer en el uso try / catch y las excepciones para implementar el flujo de control , significan que su aplicación / servicio detendrá la operación que entró en un caso excepcional .

Además, sugiero a todos que verifiquen el paradigma de falla rápida publicado por Martin Fowler (y escrito por Jim Shore) . Así es como siempre entendí cómo manejar las excepciones, incluso antes de llegar a este documento hace algún tiempo.

[...] considérelos Fatal-Errores es una comprensión completamente falsa de cuáles son las excepciones.

Por lo general, las excepciones reducen el flujo de algunas operaciones y se manejan para convertirlas en errores comprensibles para los humanos. Por lo tanto, parece que una excepción en realidad es un mejor paradigma para manejar casos de error y trabajar en ellos para evitar un bloqueo completo de la aplicación / servicio y notificar al usuario / consumidor que algo salió mal.

Más respuestas sobre las preocupaciones de @thewhiteambit

Por ejemplo, en caso de que falte una conexión de base de datos, el programa podría continuar excepcionalmente escribiendo en un archivo local y enviando los cambios a la base de datos una vez que esté disponible nuevamente. Se podría intentar analizar nuevamente la conversión de cadena a número no válida con la interpretación local en el idioma en la excepción, como cuando intenta el idioma inglés predeterminado para que Parse ("1,5") falle y vuelva a intentarlo con la interpretación en alemán, que es completamente bien porque usamos coma en lugar de punto como separador. Verá que estas excepciones ni siquiera deben estar bloqueando, solo necesitan un poco de manejo de excepciones.

  1. Si su aplicación puede funcionar sin conexión sin datos persistentes en la base de datos, no debe usar excepciones , ya que la implementación del flujo de control try/catchse considera un antipatrón. El trabajo fuera de línea es un posible caso de uso, por lo que implementa el flujo de control para verificar si la base de datos es accesible o no, no espere hasta que sea inaccesible .

  2. El análisis también es un caso esperado ( no un CASO EXCEPCIONAL ). Si espera esto, ¡no use excepciones para controlar el flujo! . ¡Obtiene algunos metadatos del usuario para saber cuál es su cultura y utiliza formateadores para esto! .NET también admite este y otros entornos, y una excepción porque se debe evitar el formateo de números si espera un uso específico de su aplicación / servicio .

Una excepción no controlada generalmente se convierte en un error, pero las excepciones en sí no son codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors

Este artículo es solo una opinión o un punto de vista del autor.

Dado que Wikipedia también puede ser solo la opinión del autor o los autores de la articulación, no diría que es el dogma , pero compruebe lo que dice el artículo de Codificación por excepción en algún párrafo:

[...] El uso de estas excepciones para manejar errores específicos que surgen para continuar con el programa se denomina codificación por excepción. Este antipatrón puede degradar rápidamente el software en rendimiento y mantenibilidad.

También dice en alguna parte:

Uso de excepción incorrecto

A menudo, la codificación por excepción puede provocar problemas adicionales en el software con el uso incorrecto de excepciones. Además de utilizar el manejo de excepciones para un problema único, el uso incorrecto de excepciones lo lleva más lejos al ejecutar código incluso después de que se genere la excepción. Este método de programación deficiente se parece al método goto en muchos lenguajes de software, pero solo ocurre después de que se detecta un problema en el software.

Honestamente, creo que el software no se puede desarrollar, no se tome en serio los casos de uso. Si sabes eso ...

  • Su base de datos puede desconectarse ...
  • Algunos archivos se pueden bloquear ...
  • Es posible que algunos formatos no sean compatibles ...
  • Alguna validación de dominio puede fallar ...
  • Su aplicación debería funcionar en modo fuera de línea ...
  • cualquiera que sea el caso de uso ...

... no usarás excepciones para eso . Se podría apoyar estos casos de uso que utilizan flujo de control regular.

Y si no se cubre algún caso de uso inesperado, su código fallará rápidamente, porque arrojará una excepción . Correcto, porque una excepción es un caso excepcional .

Por otro lado, y finalmente, a veces cubre casos excepcionales arrojando excepciones esperadas , pero no las arroja para implementar el flujo de control. Lo hace porque desea notificar a las capas superiores que no admite algún caso de uso o que su código no funciona con algunos argumentos o datos / propiedades del entorno.

Matías Fidemraizer
fuente
6

La única vez que debe preocupar a sus usuarios por algo que sucedió en el código es si hay algo que puedan o necesiten hacer para evitar el problema. Si pueden cambiar los datos en un formulario, presione un botón o cambie la configuración de una aplicación para evitar el problema y luego infórmeles. Pero las advertencias o errores que el usuario no tiene la capacidad de evitar solo los hace perder la confianza en su producto.

Las excepciones y los registros son para usted, el desarrollador, no para su usuario final. Comprender lo correcto cuando se detecta cada excepción es mucho mejor que simplemente aplicar alguna regla de oro o confiar en una red de seguridad para toda la aplicación.

La codificación sin sentido es el ÚNICO tipo de codificación incorrecta. El hecho de que sienta que hay algo mejor que se puede hacer en esas situaciones muestra que está involucrado en una buena codificación, pero evite tratar de sellar alguna regla genérica en estas situaciones y entienda la razón de que algo arroje en primer lugar y qué puedes hacer para recuperarte de ello.

ChrisCW
fuente
6

Sé que esta es una pregunta antigua, pero aquí nadie mencionó el artículo de MSDN, y fue el documento que realmente me lo aclaró, MSDN tiene un muy buen documento sobre esto, debe detectar excepciones cuando se cumplen las siguientes condiciones:

  • Comprende bien por qué se puede generar la excepción y puede implementar una recuperación específica, como solicitar al usuario que ingrese un nuevo nombre de archivo cuando detecte un objeto FileNotFoundException.

  • Puede crear y lanzar una nueva excepción más específica.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • Desea manejar parcialmente una excepción antes de pasarla para un manejo adicional. En el siguiente ejemplo, se utiliza un bloque catch para agregar una entrada a un registro de errores antes de volver a generar la excepción.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

Sugeriría leer toda la sección " Manejo de excepciones y excepciones " y también las Mejores prácticas para excepciones .

Hamid Mosalla
fuente
1

El mejor enfoque es el segundo (el que especifica el tipo de excepción). La ventaja de esto es que sabe que este tipo de excepción puede ocurrir en su código. Está manejando este tipo de excepción y puede reanudar. Si se produce alguna otra excepción, eso significa que algo está mal y que lo ayudará a encontrar errores en su código. La aplicación finalmente se bloqueará, pero se dará cuenta de que hay algo que se perdió (error) que debe corregirse.

fhnaseer
fuente
1

Con excepciones, intento lo siguiente:

Primero, atrapo tipos especiales de excepciones, como división por cero, operaciones de E / S, etc., y escribo código de acuerdo con eso. Por ejemplo, una división por cero, dependiendo de la procedencia de los valores, podría alertar al usuario (por ejemplo, una calculadora simple en que en un cálculo medio (no los argumentos) llega a una división por cero) o para tratar silenciosamente esa excepción, registrando y seguir procesando.

Luego trato de atrapar las excepciones restantes y registrarlas. Si es posible, permita la ejecución del código; de lo contrario, avise al usuario de que ocurrió un error y pídale que envíe un informe de error.

En código, algo como esto:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}
Hechicero86pt
fuente
1
Dividir entre cero excepciones y similares se manejan mejor buscando un 0numerador de antemano, en lugar de a try-catch. Además, ¿por qué tomar el genérico Exceptionaquí? Es mejor dejar que el error brote que lidiar con él aquí en todos los casos en que no lo espere.
Keith
Lea mejor lo que he escrito sobre el ejemplo que he dado: observe el "no en argumentos". Por supuesto, cualquier calculadora debe verificar los argumentos dados. Lo que hablé fue sobre los pasos intermedios. En ese punto, la verificación del argumento del usuario ya sucedió. Además, en algunas aplicaciones, es mejor evitar excepciones a la burbuja. Algunas aplicaciones deben tratar las excepciones de forma silenciosa, mientras que otras deben tratar las excepciones como errores. Un servidor web, por ejemplo, debe ejecutarse incluso cuando se producen excepciones, donde el software médico (máquinas de rayos X, por ejemplo) debe abortar cuando se producen excepciones.
Sorcerer86pt
Todavía no hay aplicaciones deben siempre tratar excepciones en silencio. Ocasionalmente, tiene una excepción que el código puede manejar, pero dicho uso debe ser raro y específico para la excepción esperada. Su ejemplo de un servidor web es pobre: ​​debe tener opciones de configuración que le permitan elegir cómo se registran los errores y si se muestran con detalles o solo una página HTTP 500, pero nunca deben ignorar los errores en silencio.
Keith
Estoy tratando de descubrir qué es lo que realmente motiva a las personas a agregar un sinónimo más de "ir a". Pero con respecto a la división por cero, este sería el UNO tipo de excepción que puedo ver que justifica la mejora del lenguaje. ¿Por qué? Porque bien puede ser el caso de que A) cero es estadísticamente un infinitesimal en su conjunto de datos, y B) usar (permitir) una excepción puede ser mucho más eficiente, porque hacer la división es una forma de probar un divisor cero. Cuando A y B son verdaderas, la ejecución promedio de su programa será más rápida usando una excepción, e incluso podría ser más pequeña.
Mike Layton
1

El segundo enfoque es bueno.

Si no desea mostrar el error y confundir al usuario de la aplicación mostrando una excepción de tiempo de ejecución (es decir, un error) que no está relacionado con ellos, simplemente registre el error y el equipo técnico puede buscar el problema y resolverlo.

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

Le recomiendo que elija el segundo enfoque para toda su aplicación.

Pranay Rana
fuente
2
El segundo enfoque no muestra al usuario que se ha producido un error; por ejemplo, si estuvieran guardando algo, no sabrían que ha fallado. catchlos bloques siempre deben llamar throwpara que se active la excepción o devolver algo / mostrar algo que le dice al usuario que la acción ha fallado. Desea recibir la llamada de soporte cuando no pueden guardar lo que sea, no 6 meses después cuando intentan recuperarlo y no pueden encontrarlo.
Keith
0

Dejar un bloque de captura en blanco es lo peor que puede hacer. Si hay un error, la mejor manera de manejarlo es:

  1. Inicie sesión en el archivo \ base de datos, etc.
  2. Intenta arreglarlo sobre la marcha (tal vez intente una forma alternativa de hacer esa operación)
  3. Si no podemos solucionarlo, notifique al usuario que hay algún error y, por supuesto, cancele la operación.
Stasel
fuente
0

Para mí, manejar la excepción puede verse como una regla de negocios. Obviamente, el primer enfoque es inaceptable. El segundo es mejor y podría ser 100% correcto si el contexto lo dice. Ahora, por ejemplo, está desarrollando un complemento de Outlook. Si agrega una excepción no controlada, el usuario de Outlook ahora puede saberlo ya que el Outlook no se destruirá a sí mismo debido a que un complemento falló. Y tienes dificultades para descubrir qué salió mal. Por lo tanto, el segundo enfoque en este caso, para mí, es correcto. Además de registrar la excepción, puede decidir mostrar un mensaje de error al usuario; lo considero como una regla comercial.

Thai Anh Duc
fuente
0

La mejor práctica es lanzar una excepción cuando se produce el error. Porque se ha producido un error y no debe ocultarse.

Pero en la vida real puedes tener varias situaciones cuando quieres ocultar esto

  1. Confía en un componente de terceros y desea continuar el programa en caso de error.
  2. Tiene un caso comercial que necesita continuar en caso de error
Gregory Nozik
fuente
66
No. No , no tirar Exception. Nunca. Lanza una subclase apropiada de Exceptiontodo lo que quieras, pero nunca Exceptionporque eso no proporciona absolutamente ninguna información semántica. De plano no puedo ver un escenario en el que tenga sentido lanzar, Exceptionpero no una subclase del mismo.
un CVn
0

El catchsin ningún argumento es simplemente comer la excepción y no sirve de nada. ¿Qué pasa si ocurre un error fatal? No hay forma de saber qué sucedió si usas catch sin argumento.

Una instrucción catch debería capturar excepciones más específicas como FileNotFoundExceptiony luego, al final , debería capturar Exceptioncuál capturaría cualquier otra excepción y las registraría.

Anirudha
fuente
¿Por qué tener un general catch(Exception)al final? Si no lo espera, siempre es una buena práctica pasarlo a la siguiente capa.
Keith
1
@Keith sí, tienes razón ... no tiene sentido detectar excepciones que no estás esperando, pero puedes hacer la excepción general para fines de registro ...
Anirudha
0

A veces es necesario tratar las excepciones que no dicen nada a los usuarios.

Mi camino es:

  • Para detectar excepciones no almacenadas en el nivel de aplicación (es decir, en global.asax) para excepciones críticas (la aplicación no puede ser útil). Estas excepciones no las estoy captando en el lugar. Simplemente inicie sesión en el nivel de aplicación y deje que el sistema haga su trabajo.
  • Captura "en el lugar" y muestra información útil al usuario (ingresó un número incorrecto, no se puede analizar).
  • Póngase al día y no haga nada en problemas marginales como "Buscaré información de actualización en segundo plano, pero el servicio no se está ejecutando".

Definitivamente no tiene que ser la mejor práctica. ;-)

Fanda
fuente
0

Puedo decirte algo:

El fragmento n. ° 1 no es aceptable porque ignora la excepción. (Se lo traga como si nada hubiera pasado).

Por lo tanto, no agregue bloque de captura que no haga nada o simplemente vuelva a lanzar.

El bloque de captura debería agregar algún valor. Por ejemplo, mensaje de salida al usuario final o error de registro.

No utilice excepciones para la lógica del programa de flujo normal. Por ejemplo:

por ejemplo, validación de entrada. <- Esta no es una situación excepcional válida, más bien debe escribir un método IsValid(myInput);para verificar si el elemento de entrada es válido o no.

Código de diseño para evitar excepciones. Por ejemplo:

int Parse(string input);

Si pasamos un valor que no se puede analizar a int, este método arrojaría una excepción, en lugar de eso podríamos escribir algo como esto:

bool TryParse(string input,out int result); <- este método devolvería un valor booleano que indica si el análisis fue exitoso.

Tal vez esto esté un poco fuera del alcance de esta pregunta, pero espero que esto te ayude a tomar decisiones correctas cuando se trata de try {} catch(){}excepciones.

Roxy'Pro
fuente