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 InvalidOperationException
cuando "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 try
bloque se detendría, el finally
bloque 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
Dispose
using
using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
finally
bloque 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
finally
puede 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 últimoreturn
nunca 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
IDisposable
interfaz (que está diseñada para liberar recursos no administrados), puede envolverlo en unausing
declaración. El compilador generará unatry {} finally {}
llamada internaDispose()
al objetofuente
Incorrecto.
finally
no 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
catch
bloque sin ningún elementothrow
.fuente
return false
ya que lanzará una excepción en su lugar @EhsanSajjadLa advertencia es porque no usó
catch
y su método básicamente está escrito así:Dado que usa
finally
únicamente para desechar, la solución preferida es utilizar elusing
patrón:Eso es suficiente, para asegurar cómo
Dispose
se 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) algunoscatch
abajo 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
false
al final del método (no es necesario para esa línea). Su método es devolver el resultado de la ejecución del comando (true
ofalse
) 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
finally
se 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
finally
no se traga ninguna excepción.fuente
No tiene un
catch
bloque, 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.
finally
Los 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
catch
bloques 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
catch
declaración vacía antes de lafinally
declaració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 false
nunca 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
finally
bloque no detectará la excepción y nunca alcanzará la última declaración de retorno.fuente
La última declaración
return false
es inalcanzable, porque al bloque try le falta unacatch
parte que manejaría la excepción, por lo que la excepción se vuelve a lanzar después delfinally
bloque 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
try
bloquereturn 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
finally
bloque 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
,finally
se 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