when - how to catch exception in c#




Por que tentar{…} finalmente{…} bom; tente{…} pegar{} ruim? (14)

"Finalmente" é uma declaração de "algo que você deve sempre fazer para garantir que o estado do programa seja são". Como tal, é sempre bom ter uma, se houver alguma possibilidade de que as exceções possam prejudicar o estado do programa. O compilador também faz grandes esforços para garantir que seu código Finally seja executado.

"Captura" é uma declaração de "Eu posso me recuperar dessa exceção". Você só deve se recuperar de exceções que você realmente pode corrigir - pegar sem argumentos diz "Ei, eu posso me recuperar de qualquer coisa!", O que é quase sempre falso.

Se fosse possível se recuperar de todas as exceções, então seria realmente uma queixa semântica, sobre o que você está declarando sua intenção de ser. No entanto, não é, e quase certamente os frames acima de vocês estarão melhor equipados para lidar com certas exceções. Assim, use finalmente seu código de limpeza gratuitamente, mas permita que mais manipuladores experientes lidem com o problema.

Eu tenho visto pessoas dizerem que é uma má forma usar o catch sem argumentos, especialmente se essa captura não fizer nada:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

No entanto, isso é considerado de boa forma:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

Tanto quanto eu posso dizer, a única diferença entre colocar código de limpeza em um bloco finally e colocar código de limpeza após os blocos try..catch é se você tiver instruções de retorno em seu bloco try (nesse caso, o código de limpeza finalmente executar, mas o código após o try..catch não vai).

Caso contrário, o que há de tão especial no final?


É uma prática ruim adicionar uma cláusula catch apenas para relançar a exceção.


A grande diferença é que try...catch engolirá a exceção, ocultando o fato de que ocorreu um erro. try..finally executará seu código de limpeza e então a exceção continuará, para ser manipulada por algo que sabe o que fazer com ele.


Bem, por um lado, é uma má prática pegar exceções que você não se importa em lidar. Confira o Capítulo 5 sobre o desempenho do .Net, aprimorando o desempenho e a escalabilidade do aplicativo .NET . Nota lateral, você provavelmente deveria estar carregando o fluxo dentro do bloco try, dessa forma, você pode pegar a exceção pertinente se falhar. Criar o fluxo fora do bloco try vence sua finalidade.


Enquanto os seguintes 2 blocos de código são equivalentes, eles não são iguais.

try
{
  int i = 1/0; 
}
catch
{
  reader.Close();
  throw;
}

try
{
  int i = 1/0;
}
finally
{
  reader.Close();
}
  1. 'finalmente' é código revelador de intenção. Você declara ao compilador e a outros programadores que esse código precisa ser executado, não importa o quê.
  2. Se você tem vários blocos catch e você tem código de limpeza, você precisa finalmente. Sem finalmente, você estaria duplicando seu código de limpeza em cada bloco catch. (Princípio DRY)

finalmente os blocos são especiais. O CLR reconhece e trata o código com um bloco finally separadamente dos blocos catch, e o CLR faz grandes esforços para garantir que um bloco finally seja sempre executado. Não é apenas o açúcar sintático do compilador.


Entre provavelmente muitas razões, as exceções são muito lentas para serem executadas. Você pode facilmente prejudicar seus tempos de execução se isso acontecer muito.


Finalmente é executado, não importa o quê. Então, se o seu bloco try tiver sucesso, ele será executado; se o bloco try falhar, ele executará o bloco catch e, em seguida, o bloco finally.

Além disso, é melhor tentar usar a seguinte construção:

using (StreamReader reader=new  StreamReader("myfile.txt"))
{
}

Como a instrução using é automaticamente quebrada em um try / finally e o fluxo será automaticamente fechado. (Você precisará colocar um try / catch em torno da instrução using se quiser realmente capturar a exceção).


Finalmente, é opcional - não há razão para ter um bloco "Finalmente" se não houver recursos para limpar.


O bloco try..finally ainda lançará quaisquer exceções levantadas. Tudo o que acontece é garantir que o código de limpeza seja executado antes que a exceção seja lançada.

O try..catch com uma captura vazia consumirá completamente qualquer exceção e ocultará o fato de que aconteceu. O leitor será fechado, mas não há como dizer se a coisa certa aconteceu. E se a sua intenção fosse escrever i no arquivo? Nesse caso, você não chegará a essa parte do código e myfile.txt estará vazio. Todos os métodos downstream lidam com isso corretamente? Quando vir o arquivo vazio, será possível adivinhar corretamente que está vazio porque foi lançada uma exceção? Melhor lançar a exceção e deixar claro que você está fazendo algo errado.

Outra razão é o try..catch feito como este é completamente incorreto. O que você está dizendo ao fazer isso é: "Não importa o que aconteça, eu posso lidar com isso". E quanto ao Exception , você pode limpar depois disso? E quanto a OutOfMemoryException ? Em geral, você deve manipular apenas as exceções que espera e sabe como manipular.


O problema com os blocos try / catch que capturam todas as exceções é que seu programa está agora em um estado indeterminado se ocorrer uma exceção desconhecida. Isso vai completamente contra a regra de falha rápida - você não quer que seu programa continue se ocorrer uma exceção. O try / catch acima poderia até capturar OutOfMemoryExceptions, mas isso é definitivamente um estado em que seu programa não será executado.

Os blocos try / finally permitem que você execute o código de limpeza enquanto ainda falha rapidamente. Para a maioria das circunstâncias, você só deseja capturar todas as exceções no nível global, para que você possa registrá-las e, em seguida, sair.


Retirado de: here

O aumento e a captura de exceções não devem ocorrer rotineiramente como parte da execução bem-sucedida de um método. Ao desenvolver bibliotecas de classes, o código do cliente deve ter a oportunidade de testar uma condição de erro antes de executar uma operação que pode resultar na criação de uma exceção. Por exemplo, System.IO.FileStream fornece uma propriedade CanRead que pode ser verificada antes de chamar o método Read, evitando que uma possível exceção seja gerada, conforme ilustrado no seguinte trecho de código:

Dim str Como Stream = GetStream () If (str.CanRead) Então 'código para ler stream End If

A decisão de verificar o estado de um objeto antes de invocar um determinado método que pode gerar uma exceção depende do estado esperado do objeto. Se um objeto FileStream é criado usando um caminho de arquivo que deve existir e um construtor que deve retornar um arquivo no modo de leitura, não é necessário verificar a propriedade CanRead; a incapacidade de ler o FileStream seria uma violação do comportamento esperado das chamadas de método feitas, e uma exceção deveria ser levantada. Por outro lado, se um método for documentado como retornando uma referência FileStream que pode ou não ser legível, é recomendável verificar a propriedade CanRead antes de tentar ler os dados.

Para ilustrar o impacto no desempenho que a técnica de codificação "executar até a exceção" pode causar, o desempenho de uma conversão, que lança uma InvalidCastException se a conversão falhar, é comparado ao operador C # como, que retorna valores nulos se uma conversão falhar. O desempenho das duas técnicas é idêntico para o caso em que a conversão é válida (consulte Teste 8.05), mas para o caso em que a conversão é inválida e usar uma conversão causa uma exceção, usar uma conversão é 600 vezes mais lento que usar a conversão como operador (ver Teste 8.06). O impacto de alto desempenho da técnica de lançamento de exceção inclui o custo de alocação, lançamento e captura da exceção e o custo da coleta de lixo subseqüente do objeto de exceção, o que significa que o impacto instantâneo de lançar uma exceção não é tão alto. À medida que mais exceções são lançadas, a coleta de lixo frequente se torna um problema, portanto, o impacto geral do uso frequente de uma técnica de codificação de lançamento de exceção será semelhante ao Teste 8.05.


Se você ler C # para programadores, você entenderá que o bloco finally foi projetado para otimizar um aplicativo e evitar vazamento de memória.

O CLR não elimina completamente os vazamentos ... vazamentos de memória podem ocorrer se o programa manter inadvertidamente referências a objetos indesejados

Por exemplo, quando você abre uma conexão de arquivo ou banco de dados, sua máquina alocará memória para atender a essa transação e essa memória será mantida a menos que o comando descartado ou próximo tenha sido executado. mas se durante a transação, um erro ocorreu, o comando procedente será terminado não a menos que esteja dentro do bloco try.. finally..

catch foi diferente de, finally no sentido de que, catch foi o design para lhe dar maneira de lidar / gerenciar ou interpretar o próprio erro. Pense nisso como uma pessoa que diz "ei, eu peguei alguns bandidos, o que você quer que eu faça com eles?" enquanto finally foi projetado para garantir que seus recursos fossem colocados corretamente. Pense nisso de alguém que se há ou não alguns caras maus ele vai se certificar de que sua propriedade ainda está segura.

E você deve permitir que os dois trabalhem juntos para o bem.

por exemplo:

try
{
  StreamReader reader=new  StreamReader("myfile.txt");
  //do other stuff
}
catch(Exception ex){
 // Create log, or show notification
 generic.Createlog("Error", ex.message);
}
finally   // Will execute despite any exception
{
  reader.Close();
}

Use Try..Catch..Finally , se o seu método souber como lidar com a exceção localmente. A exceção ocorre em Try, Handled in Catch e depois que a limpeza é feita em Finally.

No caso, se o seu método não souber como lidar com a exceção, mas precisar de uma limpeza depois de ter ocorrido, use Try..Finally

Por isso, a exceção é propagada para os métodos de chamada e manipulada se houver instruções Catch adequadas nos métodos de chamada. Se não houver manipuladores de exceção no método atual ou em qualquer um dos métodos de chamada, o aplicativo trava.

Por Try..Finally é assegurado que a limpeza local é feita antes de propagar a exceção para os métodos de chamada.


try {…} catch {} nem sempre é ruim. Não é um padrão comum, mas eu costumo usá-lo quando eu preciso desligar recursos não importa o que, como fechar um (possivelmente) sockets abertos no final de um thread.





try-catch-finally