Provocando excepciones para usar la captura

10

Para una típica if...elseenvoltura con manejo de excepciones, ¿es algo como el siguiente ejemplo una práctica recomendada para evitar la duplicación de código?

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

en vez de...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

Sé que hay un pequeño éxito en el rendimiento, pero me pregunto si esto se considera una práctica aceptable. Actualmente lo hago con el segundo método, especialmente en los casos en que necesito manejar excepciones específicas de manera diferente, pero me preguntaba si el primer método es apropiado para casos simples.

grovesNL
fuente
si el método es lo suficientemente pequeño, simplemente eliminaré el else y devolveré nulo fuera del bloque trycatch, así que tengo que devolver nulo solo una vez.
Fabio Marcolini

Respuestas:

12

Microsoft desaconseja el uso de manejo de excepciones para el control de flujo.

Y una mesa redonda sobre el tema está disponible.

Dicho esto, C # admite hacerlo, y supongo que depende de la condición encontrada si una excepción es la respuesta más adecuada.

B2K
fuente
1
Me sorprende que este tipo de cosas simplemente estén tratando de no usar eventos.
radarbob
@radarbob: ¿Cómo se relacionan los eventos con esto?
@grovesNL - ¿Lanzando una excepción en un punto específico para llamar a cierto método en un bloque catch? A los charlatanes les gusta un evento.
radarbob
@radarbob: No es un evento. Hay muchos ejemplos de casos de uso en los que esto se usaría, como se discute en el enlace de la mesa redonda de la respuesta.
1
@radarbob Solo un poco de aclaración, las excepciones fueron diseñadas como una forma de indicarle a la persona que llama que ha ocurrido algo que el método llamado no puede manejar. Sin embargo, un evento debe ser escuchado. Una excepción es una interrupción forzada del flujo normal de un programa. Una excepción no detectada hará que la aplicación completa se anule.
6

El impacto en el rendimiento es probablemente insignificante, como se explica en esta respuesta .

Así que vamos con la idea de que el rendimiento no es un problema. Estás lanzando System.Exception, solo para mover la ejecución a la catchcláusula . BadControlFlowThatShouldBeRewrittenExceptionSin embargo, arrojar un probablemente sería exagerado.

Analicemos esto. Tenemos:

  • Método GetDataFromServer(los nombres de los métodos deben ser PascalCase en C #), que posiblemente puede generar una excepción o devolver a bool.
  • Si el resultado fue true, corre ProcessData.
  • Regrese de nullotra manera.

Parece que el método donde se escribe este código es simplemente hacer demasiadas cosas. GetDataFromServerdevolver un boolaspecto parece un defecto de diseño, esperaría que ese método devuelva los datos que está obteniendo del servidor , algunos IEnumerable<SomeType>que contendrían 0 o más elementos, es decir, la ruta feliz devuelve n elementos donde n> 0 , no tan feliz ruta devuelve 0 elementos, y la ruta infeliz explota con una excepción no controlada, sea lo que sea.

Eso cambia bastante el aspecto del método; de nuevo, es difícil saber si esto tiene sentido, porque la publicación original solo tiene un punto de salida (y, por lo tanto, no se compilaría, ya que no todas las rutas de código devuelven un valor ), por lo que esto es solo una suposición descabellada:

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

Aquí mirarías ProcessDatay verías que está iterando resulty devuelve nullsi no hay ningún elemento en el IEnumerable.

Ahora, ¿por qué regresa el método null? El servidor estaba caído? ¿Hay algún error en la consulta? ¿La cadena de conexión está usando las credenciales incorrectas? Cada vez que GetDataFromServerexplota con una excepción que no espera, lo está tragando, metiéndolo debajo de la alfombra y devolviendo un nullvalor. Recomiendo capturar excepciones específicas en este caso, y registrar todo lo demás; la depuración será mucho más fácil de esa manera.

Con una catchcláusula general que no captura la excepción, se hace bastante difícil diagnosticar algo. Mínimamente haría esto en su lugar:

catch(Exception e)
{
    return null;
}

Ahora al menos puede romper e inspeccionar esi las cosas salen mal.


TL; DR : No, lanzar y capturar excepciones para el control de flujo no es una buena idea.

Mathieu Guindon
fuente
Esta respuesta demuestra exactamente por qué traté de mantener mi código genérico: no quería enumerar cada excepción que realmente hago en mi código; No quería enumerar los nombres reales de los métodos; No quería enumerar la declaración del método; No quería sugerencias de sintaxis. Tenía una sola pregunta sobre si lanzar excepciones para el control de flujo estaba bien, lo que B2K respondió rápidamente. Me encantaría debatir esto en meta.
3
Parece que esto debería haber sido una pregunta para los programadores entonces. revisamos código, no ideas.
Malaquías
2

en su primera respuesta hay un éxito en el rendimiento que no necesita estar allí.

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

cuando sale de la instrucción if para ingresar a la instrucción Catch cuando no tiene que hacer que el código cambie de dirección, por así decirlo.

si desea return null; hacerlo en la instrucción else no en una captura que se captura después de ser arrojada desde la instrucción else.

Probablemente no se aplica a su código Real , pero para el código genérico que le dio sí se aplica.

Los estándares dicen que no debes hacer esto.

Los estándares dicen que debe hacerlo así (nuevamente basado en el Código Genérico dado en OP)

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

y dado que no tiene ninguna excepción específica que esté atrapando, ni siquiera debería intentar probar aquí.

desea ver Excepciones cuando ocurren para que pueda solucionar el problema que crea la excepción.

Malaquías
fuente
1

¿Por qué no lo más simple?

if (!GetDataFromServer()) return null;
ProcessData();

Si va a existir un controlador de excepción, debería estar en ProcessData ()

Loren Pechtel
fuente
¿Por qué no querría pasar las excepciones ProcessData()al nivel más alto?
grovesNL
@grovesNL Nada útil se estaba haciendo con la excepción aquí.
Loren Pechtel
1
¿Cómo es eso? Si ProcessData()arroja una excepción ahora no se maneja. Quiero que sea a return nulleste nivel si ProcessData()arroja una excepción, sin modificarse ProcessData().
grovesNL