Encontré esta nueva característica en C # que permite que se ejecute un controlador de captura cuando se cumple una condición específica.
int i = 0;
try
{
throw new ArgumentNullException(nameof(i));
}
catch (ArgumentNullException e)
when (i == 1)
{
Console.WriteLine("Caught Argument Null Exception");
}
Estoy tratando de entender cuándo esto puede ser útil.
Un escenario podría ser algo como esto:
try
{
DatabaseUpdate()
}
catch (SQLException e)
when (driver == "MySQL")
{
//MySQL specific error handling and wrapping up the exception
}
catch (SQLException e)
when (driver == "Oracle")
{
//Oracle specific error handling and wrapping up of exception
}
..
pero esto es nuevamente algo que puedo hacer dentro del mismo controlador y delegar a diferentes métodos dependiendo del tipo de controlador. ¿Esto hace que el código sea más fácil de entender? Podría decirse que no.
Otro escenario en el que puedo pensar es algo como:
try
{
SomeOperation();
}
catch(SomeException e)
when (Condition == true)
{
//some specific error handling that this layer can handle
}
catch (Exception e) //catchall
{
throw;
}
De nuevo, esto es algo que puedo hacer como:
try
{
SomeOperation();
}
catch(SomeException e)
{
if (condition == true)
{
//some specific error handling that this layer can handle
}
else
throw;
}
¿El uso de la función 'atrapar, cuando' hace que el manejo de excepciones sea más rápido porque el controlador se omite como tal y el desenrollado de la pila puede ocurrir mucho antes en comparación con el manejo de casos de uso específicos dentro del controlador? ¿Existen casos de uso específicos que se ajusten mejor a esta función y que las personas puedan adoptar como una buena práctica?
fuente
when
necesita acceder a la excepción en sítry..catch...catch..catch..finally
?catch (Exception ex)
, verificar el tipo y lothrow
contrario. El código un poco más organizado (también conocido como evitar el ruido del código) es exactamente la razón por la que existe esta función. (Esto es cierto para muchas funciones.)Respuestas:
Los bloques de captura ya le permiten filtrar por el tipo de excepción:
La
when
cláusula le permite extender este filtro a expresiones genéricas.Por lo tanto, usa la
when
cláusula para los casos en los que el tipo de excepción no es lo suficientemente distinto para determinar si la excepción debe manejarse aquí o no.Un caso de uso común son los tipos de excepción, que en realidad son un contenedor para múltiples tipos de errores diferentes.
Aquí hay un caso que realmente he usado (en VB, que ya tiene esta función durante bastante tiempo):
Lo mismo para
SqlException
, que también tiene unaErrorCode
propiedad. La alternativa sería algo así:que es posiblemente menos elegante y rompe ligeramente el rastro de la pila .
Además, puede mencionar el mismo tipo de excepción dos veces en el mismo bloque try-catch:
lo que no sería posible sin la
when
condición.fuente
catch
, ¿verdad?when
que le permite manejar el mismo tipo de excepción varias veces. Deberías mencionar eso también, ya que es una diferencia crucial. Sinwhen
obtendrá un error del compilador.De la wiki de Roslyn (el énfasis es mío):
Vale la pena demostrar el primer punto.
Si ejecutamos esto en WinDbg hasta que se alcance la excepción, e imprimimos la pila usando
!clrstack -i -a
, veremos solo el marco deA
:Sin embargo, si cambiamos el programa para usar
when
:Veremos que la pila también contiene
B
el marco de:Esa información puede ser muy útil al depurar volcados por caída.
fuente
throw;
(a diferencia dethrow ex;
) también? +1 por el efecto secundario. No estoy seguro de aprobar eso, pero es bueno conocer esa técnica.throw;
, la pila se desenrolla y pierde los valores de los parámetros.throw;
cambia un poco el seguimiento de la pila y lothrow ex;
cambia mucho.throw
perturba ligeramente el rastro de la pila. Los números de línea son diferentes cuando se usanthrow
en contraposición awhen
.Cuando se lanza una excepción, el primer paso del manejo de excepciones identifica dónde se detectará la excepción antes de desenrollar la pila; si / cuando se identifica la ubicación "captura", todos los bloques "finalmente" se ejecutan (tenga en cuenta que si una excepción escapa de un bloque "finalmente", el procesamiento de la excepción anterior puede abandonarse). Una vez que eso suceda, el código reanudará la ejecución en la "captura".
Si hay un punto de interrupción dentro de una función que se evalúa como parte de un "cuándo", ese punto de interrupción suspenderá la ejecución antes de que ocurra cualquier desenrollado de la pila; por el contrario, un punto de interrupción en una "captura" solo suspenderá la ejecución después de que se
finally
hayan ejecutado todos los controladores.Finalmente, si las líneas 23 y 27 de la
foo
llamadabar
, y la llamada en la línea 23 arroja una excepción que sefoo
detecta dentro y se vuelve a lanzar en la línea 57, el seguimiento de la pila sugerirá que la excepción ocurrió mientras se llamababar
desde la línea 57 [ubicación de la repetición] , destruyendo cualquier información sobre si la excepción ocurrió en la llamada de la línea 23 o la línea 27. Usarwhen
para evitar detectar una excepción en primer lugar evita tal perturbación.Por cierto, un patrón útil que es molestamente incómodo tanto en C # como en VB.NET es usar una llamada de función dentro de una
when
cláusula para establecer una variable que se puede usar dentro de unafinally
cláusula para determinar si la función se completó normalmente, para manejar casos en los que una función no tiene esperanzas de "resolver" ninguna excepción que se produzca, pero, no obstante, debe tomar medidas basadas en ella. Por ejemplo, si se lanza una excepción dentro de un método de fábrica que se supone que devuelve un objeto que encapsula recursos, cualquier recurso que se adquirió deberá liberarse, pero la excepción subyacente debería filtrarse hasta el llamador. La forma más limpia de manejar eso semánticamente (aunque no sintácticamente) es tener unfinally
bloquear compruebe si se produjo una excepción y, de ser así, libere todos los recursos adquiridos en nombre del objeto que ya no se devolverá. Dado que el código de limpieza no tiene ninguna esperanza de resolver la condición que causó la excepción, realmente no deberíacatch
hacerlo, solo necesita saber qué sucedió. Llamar a una función como:dentro de una
when
cláusula hará posible que la función de fábrica sepa que sucedió algo.fuente