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

whennecesita acceder a la excepción en sítry..catch...catch..catch..finally?catch (Exception ex), verificar el tipo y lothrowcontrario. 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
whencláusula le permite extender este filtro a expresiones genéricas.Por lo tanto, usa la
whenclá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 unaErrorCodepropiedad. 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
whencondición.fuente
catch, ¿verdad?whenque le permite manejar el mismo tipo de excepción varias veces. Deberías mencionar eso también, ya que es una diferencia crucial. Sinwhenobtendrá 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
Bel 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.throwperturba ligeramente el rastro de la pila. Los números de línea son diferentes cuando se usanthrowen 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
finallyhayan ejecutado todos los controladores.Finalmente, si las líneas 23 y 27 de la
foollamadabar, y la llamada en la línea 23 arroja una excepción que sefoodetecta dentro y se vuelve a lanzar en la línea 57, el seguimiento de la pila sugerirá que la excepción ocurrió mientras se llamababardesde 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. Usarwhenpara 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
whencláusula para establecer una variable que se puede usar dentro de unafinallyclá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 unfinallybloquear 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íacatchhacerlo, solo necesita saber qué sucedió. Llamar a una función como:dentro de una
whencláusula hará posible que la función de fábrica sepa que sucedió algo.fuente