Irá codificar em um incêndio declaração Finalmente se eu voltar um valor em um bloco try?

StackOverflow https://stackoverflow.com/questions/345091

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
  }
}
Foi útil?

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:

  1. Sem exceções ocorrem
  2. 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.
  3. 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top