Tenho quase certeza de que a resposta é SIM. Se eu usar um bloco Try Finalmente, mas não usar um bloco Catch, então qualquer exceção VAI surgir. Corrigir?
Alguma opinião sobre a prática em geral?
Seth
Tenho quase certeza de que a resposta é SIM. Se eu usar um bloco Try Finalmente, mas não usar um bloco Catch, então qualquer exceção VAI surgir. Corrigir?
Alguma opinião sobre a prática em geral?
Seth
Respostas:
Sim, com certeza vai. Assumindo que seu finally
bloco não lance uma exceção, é claro, caso em que isso efetivamente "substituirá" aquele que foi originalmente lançado.
Alguma opinião sobre a prática em geral?
Sim. Cuidado . Quando o seu bloco finally está em execução, é inteiramente possível que esteja em execução porque uma exceção inesperada e não tratada foi lançada . Isso significa que algo está quebrado e algo completamente inesperado pode estar acontecendo.
Nessa situação, pode-se argumentar que você não deve executar o código em blocos finally. O código no bloco finally pode ser construído para assumir que os subsistemas dos quais ele depende estão íntegros, quando na verdade eles podem estar profundamente corrompidos. O código no bloco finally pode piorar as coisas.
Por exemplo, costumo ver este tipo de coisa:
DisableAccessToTheResource();
try
{
DoSomethingToTheResource();
}
finally
{
EnableAccessToTheResource();
}
O autor deste código está pensando "Estou fazendo uma mutação temporária no estado do mundo; preciso restaurar o estado ao que era antes de ser chamado". Mas vamos pensar em todas as maneiras como isso pode dar errado.
Primeiro, o acesso ao recurso já pode ser desabilitado pelo chamador; nesse caso, este código o reativa, possivelmente prematuramente.
Em segundo lugar, se DoSomethingToTheResource lançar uma exceção, é a coisa certa a fazer para permitir o acesso ao recurso ??? O código que gerencia o recurso é quebrado inesperadamente . Este código diz, com efeito, "se o código de gerenciamento for quebrado, certifique-se de que outro código possa chamar esse código quebrado o mais rápido possível, para que ele também possa falhar terrivelmente ." Isso parece uma má ideia.
Terceiro, se DoSomethingToTheResource lançar uma exceção, então como sabemos que EnableAccessToTheResource também não lançará uma exceção? Qualquer que seja o problema com o uso do recurso, também pode afetar o código de limpeza, caso em que a exceção original será perdida e o problema será mais difícil de diagnosticar.
Eu tendo a escrever código assim sem usar blocos try-finally:
bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
EnableAccessToTheResource();
Agora, o estado não sofre mutação, a menos que seja necessário. Agora, o estado do chamador não é alterado. E agora, se DoSomethingToTheResource falhar, não reativamos o acesso. Presumimos que algo está profundamente danificado e não corremos o risco de piorar a situação tentando manter o código em execução. Deixe o chamador lidar com o problema, se puder.
Então, quando é uma boa ideia executar um bloco finally? Primeiro, quando a exceção é esperada. Por exemplo, você pode esperar que uma tentativa de bloquear um arquivo possa falhar, porque outra pessoa o bloqueou. Nesse caso, faz sentido capturar a exceção e relatá-la ao usuário. Nesse caso, a incerteza sobre o que está quebrado é reduzida; é improvável que você piore as coisas limpando.
Em segundo lugar, quando o recurso que você está limpando é um recurso escasso do sistema. Por exemplo, faz sentido fechar um identificador de arquivo em um bloco finally. (Um "uso" é, obviamente, apenas outra maneira de escrever um bloco try-finally.) O conteúdo do arquivo pode estar corrompido, mas não há nada que você possa fazer sobre isso agora. O identificador de arquivo será fechado eventualmente, então pode ser mais cedo ou mais tarde.