Irá codificar em um incêndio declaração Finalmente se eu voltar um valor em um bloco try?
-
19-08-2019 - |
Pergunta
Eu estou revendo alguns códigos para um amigo e dizer que ele estava usando um dentro de instrução de retorno de um try-finally bloco. Será que o código no fim secção ainda disparar mesmo que o resto do bloco try não?
Exemplo:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
Solução
A resposta é simples: Sim.
Outras dicas
Normalmente, sim. O finalmente secção é garantido para executar tudo o que acontece incluindo exceções ou instrução de retorno. Uma exceção a esta regra é uma exceção assíncrona acontecendo na thread (OutOfMemoryException
, StackOverflowException
).
Para saber mais sobre exceções assíncronas e código de confiança em que situações, ler sobre regiões de execução restrita .
Aqui está um pequeno teste:
class Class1
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("before");
Console.WriteLine(test());
Console.WriteLine("after");
}
static string test()
{
try
{
return "return";
}
finally
{
Console.WriteLine("finally");
}
}
}
O resultado é:
before
finally
return
after
Citando MSDN
finalmente é usado para garantir um bloco de declaração de executa o código, independentemente de como o anterior tente bloco é Exited .
Geralmente sim, o finalmente será executado.
Para os três cenários seguintes, o finalmente irá Sempre executar:
- Sem exceções ocorrem
- exceções síncronos (exceções que ocorrem no fluxo normal do programa).
Isto inclui CLS exceções compatíveis que derivam de System.Exception e não-CLS exceções compatíveis, que não derivam de System.Exception. exceções não compatível com CLS são automaticamente envolto pela RuntimeWrappedException. C # não pode lançar exceções reclamação não-CLS, mas linguagens como C ++ lata. C # pode ser pôr em código escrito em uma linguagem que pode lançar exceções não compatível com CLS. - Asynchronous ThreadAbortException
Como de NET 2.0, um ThreadAbortException deixará de evitar uma finalmente de correr. ThreadAbortException agora é içado para antes ou depois do fim. O finalmente sempre será executado e não será interrompido por um abort segmento, enquanto a tentativa foi realmente entrou antes do abort segmento ocorreu.
O cenário seguinte, o finalmente não será executado:
Asynchronous StackOverflowException.
A partir de 2,0 .NET um excesso de pilha vai provocar o encerramento do processo. O finalmente não será executado, a menos que uma restrição adicional é aplicado para fazer a finalmente, um CER (Região de execução restrita). RCEs não deve ser usado no código do usuário em geral. Eles só devem ser usados ??onde é fundamental que código de limpeza sempre correr - depois de todo o processo está a ser encerrado em estouro de pilha de qualquer maneira e todos os objetos gerenciados será, portanto, limpos-up por padrão. Assim, o único lugar a CER deve ser relevante é para recursos que estão alocados fora do processo, por exemplo, alças não gerenciados.
Normalmente, o código não gerenciado é envolto por uma classe gerenciada antes de ser consumido pelo código do usuário. A classe wrapper gerenciado normalmente fazem uso de um SafeHandle para embrulhar a alça não gerenciado. Os implementos SafeHandle um finalizador crítico, e um método de liberação que é executado em um CER para garantir a execução do código de limpeza. Por esta razão, você não deve ver RCEs espalhados durante todo o código do usuário.
Assim, o fato de que o finalmente não é executado em StackOverflowException não deve ter nenhum efeito para o código do usuário, uma vez que o processo irá terminar de qualquer maneira. Se você tem algum caso extremo em que você precisa fazer para algum recurso clean-up não gerenciado, fora de um SafeHandle ou CriticalFinalizerObject, em seguida, usar uma CER da seguinte forma; Mas observe, esta é uma prática ruim - o conceito não gerenciado deve ser abstraído para uma classe gerenciada (es) e apropriar SafeHandle (s) pelo projeto
.por exemplo.,
// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// This is *NOT* a CER
}
finally
{
// This is a CER; guaranteed to run, if the try was entered,
// even if a StackOverflowException occurs.
}
Há uma exceção muito importante para isto que eu não vi mencionado em quaisquer outras respostas, e que (após a programação em C # por 18 anos) Eu não posso acreditar que eu não sabia.
Se você jogar ou acionar uma exceção de qualquer tipo dentro do seu bloco catch
(não apenas StackOverflowExceptions
estranho e coisas dessa laia), e você não tem todo o bloco try/catch/finally
dentro de outro bloco try/catch
, seu bloco finally
não serão executados. Isto é facilmente demonstrado - e se eu não tivesse visto eu mesmo, dada a forma como muitas vezes eu li que é apenas muito estranho, pequenas angulares casos que podem causar um bloco finally
não executar, eu não teria acreditado.
static void Main(string[] args)
{
Console.WriteLine("Beginning demo of how finally clause doesn't get executed");
try
{
Console.WriteLine("Inside try but before exception.");
throw new Exception("Exception #1");
}
catch (Exception ex)
{
Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception).");
throw;
}
finally
{
Console.WriteLine("This never gets executed, and that seems very, very wrong.");
}
Console.WriteLine("This never gets executed, but I wasn't expecting it to.");
Console.ReadLine();
}
Eu tenho certeza que há uma razão para isso, mas é bizarro que não é mais amplamente conhecido. (É notado aqui por exemplo, mas não em qualquer lugar nesta questão particular.)
Eu percebo que estou atrasado para a festa, mas no cenário (diferindo o exemplo do OP), onde de fato uma exceção é lançada MSDN estados ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): " Se a exceção não é detectada, a execução do último bloco depende se os escolhe sistema operacional para desencadear uma operação desenrola exceção ".
O bloco finally é única garantida para executar se alguma outra função (como Principal) mais acima na pilha de chamadas captura a exceção. Este detalhe geralmente não é um problema porque todos os ambientes de tempo de execução (CLR e OS) C # programas executados no gratuitos maior parte dos recursos de um processo é dono quando ele sai (identificadores de arquivo etc.). Em alguns casos, pode ser crucial no entanto: A metade operação de banco de dados em andamento que você quer cometer resp. descontrair; ou alguma conexão remota que não podem ser fechados automaticamente pelo sistema operacional e blocos, em seguida, um servidor.
Sim. Isso é, de fato, esse ponto principal de um finally. A menos que ocorra algo catestrophic (falta de memória, computador desligado, etc.) a finalmente declaração deve sempre ser executado.
Ele também não fogo contra exceção não capturada e funcionando em um fio hospedado em um serviço do Windows
Finalmente não é executado quando em um segmento em execução em um serviço do Windows
finalmente, não vai correr no caso, se você está saindo do aplicativo usando System.exit (0); como em
try
{
System.out.println("try");
System.exit(0);
}
finally
{
System.out.println("finally");
}
O resultado seria apenas: tente
99% dos cenários será garantido que o código dentro do bloco finally
será executado, no entanto, acha deste cenário: Você tem um segmento que tem um try
-> finally
bloco (sem catch
) e você terá uma não processada exceção dentro desse segmento. Neste caso, o fio vai sair e seu bloco finally
não será executada (o aplicativo pode continuar a funcionar neste caso)
Este cenário é muito raro, mas é só para mostrar que a resposta não é sempre "Sim", é na maioria das vezes "Sim" e, por vezes, em condições raras, "Não".
O principal objetivo do bloco finally é executar o que está escrito no seu interior. Ele não deve depender de tudo o que acontece no try ou catch.However com System.Environment.Exit (1) a aplicação vai sair sem se mover para a próxima linha de código.