2009-04-26 19 views
40

Al usar C#, ¿hay una manera mejor de manejar múltiples tipos de excepciones en lugar de un montón de bloques de captura desagradables?¿Manejo de excepciones más elegante que varios bloques de captura?

¿Qué se considera la mejor práctica para este tipo de situación?

Por ejemplo:

try 
{ 
    // Many types of exceptions can be thrown 
} 
catch (CustomException ce) 
{ 
    ... 
} 
catch (AnotherCustomException ace) 
{ 
    ... 
} 
catch (Exception ex) 
{ 
    ... 
} 

Respuesta

68

En mi opinión, un montón de bloques catch "feo" es la mejor manera de manejar esa situación.

La razón por la que prefiero esto es que es muy explícito. Está indicando explícitamente qué excepciones desea controlar y cómo se deben manejar. Otras formas de tratar de combinar el manejo en formas más concisas pierden legibilidad en la mayoría de los casos.

Mi consejo sería seguir con esto, y manejar las excepciones que desea manejar de forma explícita, cada una en su propio bloque catch.

+0

¿Ve algún inconveniente en la solución de filtro de Mark Brackett? – TrueWill

+0

@TrueWill: IMO, solo reduce el mantenimiento, sin realmente agregar mucha funcionalidad. Habiendo dicho eso, no es horrible, simplemente no es obvio. –

10

Desafortunadamente, C# does not have user exception filters como VB.NET, por lo que está limitado a:

  1. La captura de un ancestro común a todas las excepciones. Esto puede ser o no lo que desee, ya que puede haber otros tipos de excepciones descendientes que no desee capturar.
  2. Mover la lógica de manejo de excepciones a otro método y llamarlo desde cada controlador.
  3. Repitiendo la lógica de excepción para cada manejador.
  4. Mover la lógica de manejo de excepciones a un lenguaje que admita filtros, como VB.NET.
+5

A partir de la especificación del lenguaje C# 6.0 (nuevo en .NET 4.6/Visual Studio 2015), C# admite "Filtros de excepción" con la sintaxis: 'catch (Exception ex) if (ex.Message.Contains (" Fatal "))' . – qJake

21

Estoy de acuerdo con Reed: este es el mejor enfoque.

me gustaría añadir estos comentarios:

única pega algo que va a hacer algo al respecto. Si no puede solucionar el problema, no tiene sentido capturar una excepción específica.

No exagere el uso de bloques de captura. En muchos casos en los que no puede resolver la excepción, lo mejor es dejar que la excepción salte a un punto central (como Page_Error) y atraparla allí. Luego, registra la excepción y muestra un mensaje al usuario.

+6

+1: gran punto acerca de no detectar excepciones "adicionales". Estuve tratando de mencionar eso (al decir que hace que seas explícito sobre lo que quieres manejar), pero tienes razón, por lo general no debes manejarlo todo, a menos que lo manejes de manera significativa. camino. –

+1

También +1. Quiero agregar que a veces los desarrolladores agregan bloques catch a todos los métodos para que puedan rastrear qué método arrojó realmente la excepción. ¡Para eso es el rastro de la pila! –

-6

Catch sólo lo que necesita para resolver específicamente y dejar

catch(Exception e) 
{ 
} 

para todo lo demás (o evitarlo y dar esta excepciones a la pila)

+6

¿No se tragará la excepción entera, que casi siempre es una mala idea? – Ben

+4

Sí, este es un pedazo de código INCORRECTO, tal como está. Creo que Mash estaba insinuando que tiraste allí ... o eso o estaba borracho. – Maverick

1

Usted debe comprobar fuera de la Enterprise Library Exception Handling block. Permite un control mucho más fino de las excepciones a través de políticas (políticas de ajuste, políticas de propagación, políticas de reemplazo, políticas de registro, etc.) Puede usarlo para estandarizar la forma en que codifica un bloque de excepción y usa la configuración para manejar con precisión lo que sucede con un tipo particular de excepción.

15

Sobre la única otra cosa que puede hacer es emular a los filtros de excepción de VB.NET:

try { 
    DoSomething(); 
} catch (Exception e) { 
    if (!ex is CustomException && !ex is AnotherCustomException) { 
     throw; 
    } 
    // handle 
} 

A veces esto es mejor, a veces no.Lo usaría principalmente si hubiera alguna lógica común que quisiera en el controlador, pero las excepciones no comparten un tipo base.

+2

La lógica negativa hace que mi ojo izquierdo se sienta divertido. En un caso como este, ¿qué tal 'if (! (Ex es CustomException || ex es AnotherCustomException))'? – Craig

+3

Eso sigue siendo una lógica negativa, usted acaba de ejecutar De Morgan en eso. La legibilidad es discutiblemente mala de cualquier manera. Haría algo como 'if (ex es CustomException || ex es AnotherCustomException) {/ * handle * /} else {throw; } 'o' bool canHandle = ex es CustomException || ex es AnotherCustomException; if (! canHandle) throw;/* handle */' – Timbo

0

¿De esta manera no es bueno?

Si desea manejar una sola excepción:

try 
{ 
    // Many types of exceptions can be thrown 
} 
catch (TheExceptionIWantToHandle ex) 
{ 
    // handle it 
} 
catch (Exception ex) 
{ 
    // suppress all other exceptions 
} 

Si desea manejar todas las excepciones, excepto uno:

try 
{ 
    // Many types of exceptions can be thrown 
} 
catch (TheExceptionIDoNotWantToHandle ex) 
{ 
    // suppress all other exceptions 
} 
catch (Exception ex) 
{ 
    // handle it 
} 

bueno, no es bueno?

+3

No es bueno, en general. No suprima excepciones sin iniciar sesión de alguna manera. De lo contrario, podría estar ocultando información importante. Además, en mi humilde opinión, hay muy pocas razones para hacer "catch (excepcion ex)", a menos que vayas a registrarlo o envolverlo, y luego usar el "throw"; declaración para permitir que se propague. –

5

Si necesita escribir una gran cantidad de código como este, le sugiero que compruebe un poco de AOP framework. Yo personalmente uso PostSharp. Entonces podría ocultar todos los códigos de manejo de excepciones en aspectos.