Solo quiero saber si es seguro / buen enfoque llamar return
dentro de un using
bloque.
Por ej.
using(var scope = new TransactionScope())
{
// my core logic
return true; // if condition met else
return false;
scope.Complete();
}
Sabemos dispose()
que se cancelará la última llave más rizada . Pero lo que será en el caso anterior, ya que return
salta el control fuera del alcance dado (AFAIK) ...
- ¿Me
scope.Complete()
llaman? - Y así para el
dispose()
método del osciloscopio .
using{}
se termina el alcance, los objetos relevantes se eliminan,return
"romperán" el alcance, por lo que los objetos se eliminarán como se esperabascope.Complete()
llamada nunca se verá afectada con la muestra que proporcionó, por lo que su transacción siempre se revertirá.using
'sdispose()
, cuando regrese, la función que contiene esteusing
bloque habrá regresado y todo lo que le pertenezca quedará huérfano. Entonces, incluso siscope
no se hubiera eliminado "porusing
" (lo será, como otros explicaron), se eliminará de todos modos porque la función terminó. Si C # tuviera unagoto
declaración, ¿ya terminaste de reír? bueno, entonces en lugar de regresar, podríagoto
hacerlo después de la llave de cierre, sin regresar. Lógicamente,scope
todavía se eliminaría, pero acaba de ponergoto
C #, así que a quién le importa la lógica en esa etapa.Respuestas:
Es perfectamente seguro llamar
return
dentro de suusing
bloque, ya que un bloque de uso es solo untry/finally
bloque.En su ejemplo anterior, después de la devolución
true
, el alcance se eliminará y se devolverá el valor.return false
Yscope.Complete()
se no ser llamado.Dispose
sin embargo, se llamará independientemente, ya que reside dentro del bloque finalmente.Su código es esencialmente el mismo que este (si eso lo hace más fácil de entender):
var scope = new TransactionScope()) try { // my core logic return true; // if condition met else return false; scope.Complete(); } finally { if( scope != null) ((IDisposable)scope).Dispose(); }
Tenga en cuenta que su transacción nunca se confirmará, ya que no hay forma de llegar
scope.Complete()
a confirmar la transacción.fuente
Dispose
se llamará. Si el OP no sabe qué sucede enusing
, es probable que no sepa qué sucedefinally
.using
, por ejemplousing (var callersVar = MyFunc(..)) ..
, en lugar de usar dentro de "MyFunc" - me refiero a que la persona que llama recibe la transmisión y es responsable de cerrarla víausing
o explícitamente, o (b) Haga que MyFunc extraiga toda la información necesaria en otros objetos, que se pueden transferir de forma segura; luego, suusing
. No debería tener que escribir código con fugas.Eso está bien: las
finally
cláusulas (que es lo que hace la llave de cierre de lausing
cláusula debajo del capó) siempre se ejecutan cuando se deja el alcance, sin importar cómo.Sin embargo, esto solo es cierto para las declaraciones que están en el bloque finalmente (que no se puede establecer explícitamente cuando se usa
using
). Por lo tanto, en su ejemplo,scope.Complete()
nunca se llamaría (aunque espero que el compilador le advierta sobre el código inalcanzable).fuente
En general, es un buen enfoque. Pero en su caso, si regresa antes de llamar al
scope.Complete()
, simplemente eliminará el TransactionScope. Depende de tu diseño.Entonces, en este ejemplo, no se llama a Complete () y se elimina el alcance, asumiendo que hereda la interfaz IDisposable.
fuente
Alcance Definitivamente se debe llamar a Complete antes
return
. El compilador mostrará una advertencia y este código nunca se llamará.Con respecto a
return
sí mismo, sí, es seguro llamarlousing
declaración interna . El uso se traduce en intentar, finalmente bloquear detrás de la escena y finalmente bloquear debe ejecutarse.fuente
En el ejemplo que ha proporcionado, hay un problema;
scope.Complete()
nunca se llama. En segundo lugar, no es una buena práctica utilizarreturn
declaraciones dentro deusing
declaraciones. Consulte lo siguiente:using(var scope = new TransactionScope()) { //have some logic here return scope; }
En este simple ejemplo, el punto es que; el valor de
scope
será nulo cuando finalice el uso de la instrucción.Así que es mejor no volver al interior usando declaraciones.
fuente
scope
no será nula - la única cosa que va a haber sucedido es queDispose()
se han invocado en esa instancia, y por lo tanto la instancia debe no utilizar más (pero no es nula y no hay nada que impida que pruebe y el uso el objeto desechado, aunque se trate de un uso inadecuado de un objeto desechable).return scope
devuelve una referencia a ese objeto. De esta forma, si asigna esa referencia a la devolución, evita que el GC limpie el objeto desechado.Para asegurarse de que
scope.Complete()
se llamará, envuélvalo contry/finally
. Sedispose
llama porque lo ha envuelto con elusing
que es untry/finally
bloque alternativo .using(var scope = new TransactionScope()) { try { // my core logic return true; // if condition met else return false; } finally { scope.Complete(); } }
fuente
En este ejemplo, scope.Complete () nunca se ejecutará. Sin embargo, el comando return limpiará todo lo que esté asignado en la pila. El GC se encargará de todo lo que no esté referenciado. Por lo tanto, a menos que haya un objeto que el GC no pueda recoger, no hay problema.
fuente