Estou revendo algum código para um amigo e digo que ele estava usando uma declaração de retorno dentro de um bloco try-finally. O código na seção Finalmente ainda é acionado, embora o restante do bloco try não seja?
Exemplo:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
c#
.net
exception-handling
try-catch
JamesEggers
fonte
fonte
StackOverflowException
,ExecutionEngineException
são algumas delas. E como eles não podem ser manipulados, ofinally
não funcionará.try
bloco. Nada sobre abortos abruptos de programas.try
bloco é umareturn
instrução. (A segunda indicação de que o bloqueio é inacessível e vai gerar um aviso.)Respostas:
Resposta simples: Sim.
fonte
finally
bloco será executado.Normalmente sim. A seção finalmente é garantida para executar o que acontecer, incluindo exceções ou declaração de retorno. Uma exceção a esta regra é uma exceção assíncrona que ocorre no encadeamento (
OutOfMemoryException
,StackOverflowException
).Para saber mais sobre exceções assíncronas e código confiável nessas situações, leia sobre regiões de execução restritas .
fonte
Aqui está um pequeno teste:
O resultado é:
fonte
WriteLine
o resultado da chamada do método é realmente realizado. Nesse caso, areturn
chamada define o resultado dos métodos, finalmente grava no console - antes que o método saia. Em seguida, oWriteLine
método in principal cospe o texto da chamada de retorno.Citando no MSDN
fonte
finally
na verdade, não garante nada, mesmo para programas perfeitamente comuns (que por acaso lançaram essa exceção).Geralmente sim, o finalmente será executado.
Para os três cenários a seguir, o finalmente será sempre executado:
Isso inclui exceções compatíveis com CLS derivadas de System.Exception e exceções não compatíveis com CLS, que não derivam de System.Exception. Exceções não compatíveis com CLS são agrupadas automaticamente pelo RuntimeWrappedException. O C # não pode gerar exceções de reclamação que não sejam do CLS, mas idiomas como o C ++ podem. O C # pode estar chamando o código escrito em um idioma que pode lançar exceções não compatíveis com CLS.
A partir do .NET 2.0, um ThreadAbortException não impedirá mais que um finalmente seja executado. ThreadAbortException agora é içado para antes ou depois do finalmente. O finalmente sempre será executado e não será interrompido por uma interrupção de encadeamento, desde que a tentativa tenha sido realmente inserida antes da ocorrência do cancelamento de encadeamento.
O cenário a seguir, o finalmente não será executado:
StackOverflowException assíncrono.
A partir do .NET 2.0, um estouro de pilha fará com que o processo seja encerrado. O finalmente não será executado, a menos que uma restrição adicional seja aplicada para tornar o finalmente um CER (Região de Execução Restrita). As RCEs não devem ser usadas no código geral do usuário. Eles devem ser usados apenas onde for crítico que o código de limpeza sempre seja executado - depois que todo o processo for encerrado pelo excesso de pilha de qualquer maneira e, portanto, todos os objetos gerenciados serão limpos por padrão. Portanto, o único local em que um CER deve ser relevante é para recursos alocados fora do processo, por exemplo, identificadores não gerenciados.
Normalmente, o código não gerenciado é agrupado por alguma classe gerenciada antes de ser consumido pelo código do usuário. A classe de wrapper gerenciado normalmente usa um SafeHandle para quebrar o identificador não gerenciado. O SafeHandle implementa um finalizador crítico e um método Release que é executado em um CER para garantir a execução do código de limpeza. Por esse motivo, você não deve ver as CERs espalhadas pelo código do usuário.
Portanto, o fato de finalmente não executar no StackOverflowException não deve afetar o código do usuário, pois o processo será encerrado de qualquer maneira. Se você tem algum caso extremo em que precisa limpar algum recurso não gerenciado, fora de um SafeHandle ou CriticalFinalizerObject, use um CER da seguinte maneira; mas observe que isso é uma prática ruim - o conceito não gerenciado deve ser abstraído para uma classe gerenciada e SafeHandle (s) apropriado (s) por design.
por exemplo,
fonte
FailFast
internamente. A única maneira de conseguir capturá-los é personalizando a hospedagem de tempo de execução do CLR . Observe que seu ponto ainda é válido para outras exceções assíncronas.Há uma exceção muito importante a isso, que não vi mencionada em nenhuma outra resposta, e que (depois de programar em C # há 18 anos) não acredito que não sabia.
Se você lançar ou disparar uma exceção de qualquer tipo dentro do seu
catch
bloco (não apenas esquisitoStackOverflowExceptions
e coisas desse tipo), e você não tiver otry/catch/finally
bloco inteiro dentro de outrotry/catch
bloco, seufinally
bloco não será executado. Isso é facilmente demonstrado - e se eu não o tivesse visto, dada a frequência com que li que são apenas pequenas caixas de esquina realmente estranhas que podem fazer com que umfinally
bloco não seja executado, eu não teria acreditado.Tenho certeza de que há uma razão para isso, mas é bizarro que não seja mais conhecido. (Ele está anotado aqui, por exemplo, mas não em nenhum lugar desta pergunta em particular.)
fonte
finally
bloco simplesmente não é um problema para ocatch
bloco.Sei que estou atrasado para a festa, mas no cenário (diferente do exemplo do OP) em que de fato uma exceção é lançada, os estados do MSDN ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): "Se a exceção não for capturada, a execução do bloco final depende se o sistema operacional escolhe acionar uma operação de desenrolamento de exceção."
O bloco final é garantido apenas para execução se alguma outra função (como Principal) mais adiante na pilha de chamadas capturar a exceção. Esse detalhe geralmente não é um problema porque todos os programas C # de ambientes de tempo de execução (CLR e OS) são executados gratuitamente na maioria dos recursos que um processo possui quando sai (manipula arquivos etc.). Em alguns casos, pode ser crucial: Uma operação de banco de dados parcialmente em andamento que você deseja confirmar. descontrair; ou alguma conexão remota que talvez não seja fechada automaticamente pelo SO e bloqueie um servidor.
fonte
Sim. Esse é, de fato, o ponto principal de uma declaração finalmente. A menos que algo catastrófico ocorra (falta de memória, computador desconectado etc.), a instrução finalmente deve sempre ser executada.
fonte
finally
bloco se essa exceção nunca for capturada. Isso me pegou de surpresa ;-).Ele também não dispara na exceção não capturada e é executado em um thread hospedado em um Serviço do Windows
Finalmente não é executado quando em um Thread em execução em um Serviço do Windows
fonte
finalmente não será executado caso você esteja saindo do aplicativo usando System.exit (0); como em
o resultado seria apenas: tente
fonte
c#
, mas isso parece serJava
. E, além disso, na maioria dos casosSystem.exit()
é um indício de uma má concepção :-)Em 99% dos cenários, será garantido que o código dentro do
finally
bloco será executado, no entanto, pense neste cenário: Você possui um encadeamento que possui umtry
->finally
block (nocatch
) e recebe uma exceção não tratada dentro desse encadeamento. Nesse caso, o encadeamento sairá e seufinally
bloco não será executado (o aplicativo pode continuar sendo executado nesse caso)Esse cenário é bastante raro, mas é apenas para mostrar que a resposta não é SEMPRE "Sim", na maioria das vezes é "Sim" e, às vezes, em raras condições, "Não".
fonte
O principal objetivo do bloco finalmente é executar o que estiver escrito dentro dele. No entanto, com o System.Environment.Exit (1), o aplicativo será encerrado sem passar para a próxima linha de código.
fonte