Este código es parte de una aplicación que lee y escribe en una base de datos conectada a ODBC. Crea un registro en la base de datos y luego verifica si se ha creado correctamente un registro y luego regresa true.
Mi comprensión del flujo de control es la siguiente:
command.ExecuteNonQuery()está documentado para lanzar un InvalidOperationExceptioncuando "una llamada a un método no es válida para el estado actual del objeto". Por lo tanto, si eso sucediera, la ejecución del trybloque se detendría, el finallybloque se ejecutaría y luego se ejecutaría return false;en la parte inferior.
Sin embargo, mi IDE afirma que el return false;código es inalcanzable. Y parece ser cierto, puedo eliminarlo y se compila sin quejas. Sin embargo, para mí parece que no habría ningún valor de retorno para la ruta del código donde se lanza la excepción mencionada.
private static bool createRecord(String table,
IDictionary<String,String> data,
System.Data.IDbConnection conn,
OdbcTransaction trans) {
[... some other code ...]
int returnValue = 0;
try {
command.CommandText = sb.ToString();
returnValue = command.ExecuteNonQuery();
return returnValue == 1;
} finally {
command.Dispose();
}
return false;
}
¿Cuál es mi error de comprensión aquí?
fuente

Disposeusingusing (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }finallybloque significa algo más de lo que crees.Respuestas:
Advertencia del compilador (nivel 2) CS0162
Lo que es solo decir, el compilador comprende lo suficiente a través del análisis estático que no se puede alcanzar y lo omite por completo del IL compilado (de ahí su advertencia)
Nota : Puede probarse este hecho a sí mismo intentando pasar al código inalcanzable con el depurador o utilizando un explorador de IL.
El
finallypuede correr en una excepción , (aunque eso a un lado) no cambia el hecho (en este caso) que seguirá siendo una excepción no capturada . Ergo, el últimoreturnnunca será golpeado independientemente.Si desea que el código continúe hasta el último
return, su única opción es detectar la excepción ;Si no lo hace, déjelo como está y elimine el
return.Ejemplo
Cotizar la documentación
probar-finalmente (Referencia de C #)
Por último
Cuando use cualquier cosa que admita la
IDisposableinterfaz (que está diseñada para liberar recursos no administrados), puede envolverlo en unausingdeclaración. El compilador generará unatry {} finally {}llamada internaDispose()al objetofuente
Incorrecto.
finallyno se traga la excepción. Lo respeta y la excepción se lanzará con normalidad. Solo ejecutará el código en el final antes de que finalice el bloque (con o sin excepción).Si desea que se trague la excepción, debe usar un
catchbloque sin ningún elementothrow.fuente
return falseya que lanzará una excepción en su lugar @EhsanSajjadLa advertencia es porque no usó
catchy su método básicamente está escrito así:Dado que usa
finallyúnicamente para desechar, la solución preferida es utilizar elusingpatrón:Eso es suficiente, para asegurar cómo
Disposese llamará. Está garantizado que se llamará ya sea después de la ejecución con éxito del bloque de código o en el momento (antes) algunoscatchabajo en la pila de llamadas (llamadas de padres están abajo, ¿verdad?).Si no se tratara de deshacerse, entonces
es suficiente, ya que nunca tendrá que regresar
falseal final del método (no es necesario para esa línea). Su método es devolver el resultado de la ejecución del comando (trueofalse) o lanzará una excepción de lo contrario .Considere también lanzar sus propias excepciones envolviendo las excepciones esperadas (consulte el constructor InvalidOperationException ):
Esto se usa típicamente para decir algo más significativo (útil) para la persona que llama de lo que le diría la excepción de llamada anidada.
La mayoría de las veces, realmente no te preocupas por las excepciones no controladas. A veces, debe asegurarse de que
finallyse llame incluso si la excepción no se controla. En este caso, simplemente lo atrapa usted mismo y vuelve a lanzarlo (vea esta respuesta ):fuente
Parece que estás buscando algo como esto:
Por favor, tenga en cuenta que
finallyno se traga ninguna excepción.fuente
No tiene un
catchbloque, por lo que la excepción aún se lanza, lo que bloquea el retorno.Esto es incorrecto, porque el bloque finalmente se ejecutaría y luego habría una excepción no detectada.
finallyLos bloques se utilizan para la limpieza y no detectan la excepción. La excepción se lanza antes del retorno, por lo tanto, nunca se alcanzará el retorno, porque se lanza una excepción antes.Su IDE tiene razón en que nunca se alcanzará, porque se lanzará la excepción. Solo los
catchbloques pueden detectar excepciones.Leyendo de la documentación ,
Esto muestra claramente que el finalmente no tiene la intención de detectar la excepción, y habría estado en lo correcto si hubiera habido una
catchdeclaración vacía antes de lafinallydeclaración.fuente
Cuando se lanza la excepción, la pila se desenrollará (la ejecución saldrá de la función) sin devolver un valor, y cualquier bloque de captura en los marcos de la pila por encima de la función detectará la excepción en su lugar.
Por lo tanto,
return falsenunca se ejecutará.Intente lanzar manualmente una excepción para comprender el flujo de control:
fuente
En tu código:
Esta es la falla en su lógica porque el
finallybloque no detectará la excepción y nunca alcanzará la última declaración de retorno.fuente
La última declaración
return falsees inalcanzable, porque al bloque try le falta unacatchparte que manejaría la excepción, por lo que la excepción se vuelve a lanzar después delfinallybloque y la ejecución nunca llega a la última declaración.fuente
Tiene dos rutas de retorno en su código, la segunda de las cuales es inalcanzable debido a la primera. La última declaración en su
trybloquereturn returnValue == 1;proporciona su retorno normal, por lo que nunca puede llegarreturn false;al final del bloque de método.FWIW, el orden de ejecución relacionado con el
finallybloque es: la expresión que proporciona el valor de retorno en el bloque try se evaluará primero, luego se ejecutará el bloque finalmente y luego se devolverá el valor de la expresión calculada (dentro del bloque try).Con respecto al flujo en la excepción ... sin un
catch,finallyse ejecutará en caso de excepción antes de que la excepción se vuelva a eliminar del método; no hay camino de "retorno".fuente