Só quero saber se é seguro / bom fazer chamadas return
dentro de um using
bloco.
Por ex.
using(var scope = new TransactionScope())
{
// my core logic
return true; // if condition met else
return false;
scope.Complete();
}
Sabemos que a última chave dispose()
será cancelada. Mas o que será no caso acima, já que return
salta o controle do escopo dado (AFAIK) ...
- É meu
scope.Complete()
chamado? - E assim, para o
dispose()
método do osciloscópio .
using{}
escopo terminar, os objetos relevantesreturn
serão descartados, irão "quebrar" o escopo - então os objetos serão descartados como esperadoscope.Complete()
chamada nunca será atingida com a amostra fornecida, então sua transação sempre será revertida.using
'sdispose()
for chamado, quando você retornar, a função que contém esteusing
bloco terá retornado e tudo pertencente a ele ficará órfão. Portanto, mesmo sescope
não tivesse sido eliminado "pelousing
" (será, como outros explicaram), será eliminado de qualquer maneira porque a função foi encerrada. Se C # tivesse agoto
declaração - você já parou de rir? good- então em vez de retornar você poderiagoto
após a chave de fechamento, sem retornar. Logicamente,scope
ainda estaria descartado, mas você acabou de inserirgoto
C # para quem se importa com a lógica nesse estágio.Respostas:
É perfeitamente seguro chamar
return
dentro do seuusing
bloco, uma vez que um bloco em uso é apenas umtry/finally
bloco.Em seu exemplo acima, após o retorno
true
, o escopo será descartado e o valor retornado.return false
, e nãoscope.Complete()
será chamado.Dispose
no entanto, será chamado independentemente, pois reside dentro do bloco finally.Seu código é essencialmente o mesmo (se isso o tornar mais fácil de entender):
Esteja ciente de que sua transação nunca será confirmada, pois não há como fazer
scope.Complete()
para confirmar a transação.fonte
Dispose
será chamado. Se o OP não sabe o que acontece emusing
, é provável que ele não saiba o que acontece comfinally
.using
, por exemplousing (var callersVar = MyFunc(..)) ..
, em vez de usar dentro de "MyFunc" - quero dizer que o chamador recebe o fluxo e é responsável por fechá-lo viausing
ou explicitamente, ou (b) faça com que MyFunc extraia todas as informações necessárias para outros objetos, que podem ser passadas de volta com segurança - então os objetos de dados ou fluxo subjacentes podem ser descartados por seuusing
. Você não deve ter que escrever código que vaza.Tudo bem -
finally
cláusulas (que é o que a chave de fechamento dousing
cláusula faz sob o capô) sempre são executadas quando o escopo é deixado, não importa como.No entanto, isso só é verdadeiro para as instruções que estão no bloco finally (que não podem ser explicitamente definidas ao usar
using
). Portanto, no seu exemplo,scope.Complete()
nunca seria chamado (espero que o compilador avise sobre código inacessível).fonte
Em geral, é uma boa abordagem. Mas, no seu caso, se você retornar antes de chamar o
scope.Complete()
, isso irá destruir o TransactionScope. Depende do seu design.Portanto, neste exemplo, Complete () não é chamado e o escopo é descartado, supondo que ele herde a interface IDisposable.
fonte
scope.Complete definitivamente deve ser chamado antes
return
. O compilador exibirá um aviso e esse código nunca será chamado.Quanto a
return
si mesmo - sim, é seguro chamá-lo deusing
declaração interna . O uso é traduzido para tentar finalmente bloquear nos bastidores e finalmente bloquear deve ser executado.fonte
No exemplo que você forneceu, há um problema;
scope.Complete()
nunca é chamado. Em segundo lugar, não é uma boa prática usarreturn
instrução dentro deusing
instruções. Consulte o seguinte:Neste exemplo simples, o ponto é isso; o valor de
scope
será nulo quando o uso da instrução for concluído.Portanto, é melhor não voltar para dentro usando instruções.
fonte
scope
não será nulo - a única coisa que terá acontecido é queDispose()
terá sido invocado naquela instância e, portanto, a instância não deve ser mais usada (mas não é nulo e não há nada que o impeça de tentar e usar o objeto descartado, mesmo que seja um uso impróprio de um objeto descartável).return scope
retorna uma referência a esse objeto. Dessa forma, se você atribuir essa referência no retorno, você evita que o CG limpe o objeto descartado.Para certificar-se de que
scope.Complete()
será chamado, envolva-o comtry/finally
. Odispose
é chamado porque você o envolveu com ousing
que é umtry/finally
bloco alternativo .fonte
Neste exemplo, scope.Complete () nunca será executado. No entanto, o comando de retorno limpará tudo o que está atribuído na pilha. O GC cuidará de tudo o que não for referenciado. Então, a menos que haja um objeto que não possa ser pego pelo GC, não há problema.
fonte