Como usar o try catch para manipulação de exceção é uma prática recomendada


201

enquanto mantém o código do meu colega até mesmo de alguém que afirma ser um desenvolvedor sênior, muitas vezes vejo o seguinte código:

try
{
  //do something
}
catch
{
  //Do nothing
}

ou às vezes eles escrevem informações de log em arquivos de log como o seguinte try catchbloco

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

Só estou pensando se o que eles fizeram é a melhor prática? Isso me deixa confuso porque, na minha opinião, os usuários devem saber o que acontece com o sistema.

Por favor me dê alguns conselhos.


128
O snippet nº 1 é 99,999% do tempo inaceitável.
leppie

22
Exibir exceção diretamente para o usuário nunca é uma boa idéia, principalmente por dois motivos: 1. se for um usuário comum, ele ficará aborrecido ao ler a mensagem de erro que indica muito pouco para ele. 2. Se ele é um hacker, ele pode obter informações úteis. A melhor prática, IMO, é registrar a exceção e mostrar uma mensagem de erro amigável.
Leri

4
@leppie Se algo inesperado ocorre (como NullReferenceou ArgumentNullnão faz parte do fluxo do aplicativo), significa que há um bug que precisa ser corrigido, portanto, registrá-los ajudará a depurar seu código muito mais rapidamente.
Leri

14
O uso de um bloco try-catch para ocultar uma exceção geralmente é o resultado de uma programação lenta. É um atalho frequentemente usado em vez de escrever código de validação para testar entradas. Muito ocasionalmente, há momentos em que uma exceção pode surgir que não afeta a operação do seu código, e ocultá-lo dessa maneira pode estar OK. Isso é bastante raro, no entanto.
Corey #

12
@ Toan, bem, se for um trabalho em lotes, estou entrando no nível superior (Principal) para registrar e, em seguida, repetindo novamente para acionar um alarme de que o trabalho foi encerrado de forma anormal. Se for um aplicativo da web, estou deixando a exceção de bolha para um manipulador global, registrando e redirecionando o usuário para uma tela de erro. Seu cenário de caso de uso determina o que você faz com essa exceção depois que você a registra ou manipula.
Anthony Pegram

Respostas:


300

Minha estratégia de tratamento de exceções é:

  • Para capturar todas as exceções não tratadas, conectando oApplication.ThreadException event , e decida:

    • Para um aplicativo de interface do usuário: para enviá-lo ao usuário com uma mensagem de desculpas (winforms)
    • Para um aplicativo de Serviço ou Console: registre-o em um arquivo (serviço ou console)

Sempre incluo todos os trechos de código executados externamente em try/catch:

  • Todos os eventos disparados pela infraestrutura Winforms (Load, Click, SelectedChanged ...)
  • Todos os eventos disparados por componentes de terceiros

Em seguida, incluo 'try / catch'

  • Todas as operações que eu conheço podem não funcionar o tempo todo (operações de IO, cálculos com uma divisão zero potencial ...). Nesse caso, lancei um novo ApplicationException("custom message", innerException)para acompanhar o que realmente aconteceu

Além disso, tento o meu melhor para classificar as exceções corretamente . Há exceções que:

  • precisa ser mostrado ao usuário imediatamente
  • requer algum processamento extra para juntar as coisas quando elas acontecem, para evitar problemas de cascata (por exemplo: coloque .EndUpdate na finallyseção durante um TreeViewpreenchimento)
  • o usuário não se importa, mas é importante saber o que aconteceu. Então, eu sempre os registro:

    • No log de eventos
    • ou em um arquivo .log no disco

É uma boa prática projetar alguns métodos estáticos para lidar com exceções nos manipuladores de erro de nível superior do aplicativo.

Eu também me forço a tentar:

  • Lembre-se de que TODAS as exceções são apresentadas no nível superior . Não é necessário colocar manipuladores de exceção em todos os lugares.
  • As funções reutilizáveis ​​ou chamadas profundas não precisam exibir ou registrar exceções: elas são ativadas automaticamente ou novamente com algumas mensagens personalizadas em meus manipuladores de exceções.

Então finalmente:

Ruim:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

Sem utilidade:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

Ter uma tentativa finalmente sem capturas é perfeitamente válido:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

O que faço no nível superior:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

O que faço em algumas funções chamadas:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

Há muito a ver com o tratamento de exceções (exceções personalizadas), mas essas regras que tento manter em mente são suficientes para os aplicativos simples que faço.

Aqui está um exemplo de métodos de extensões para lidar com exceções capturadas de uma maneira confortável. Eles são implementados de uma maneira que podem ser encadeados, e é muito fácil adicionar seu próprio processamento de exceção capturada.

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}

98
catch(Exception ex) { throw ex; }em C # é pior que redundante (independentemente do tipo de exceção que você está capturando). Para rever novamente, use throw;. Com o primeiro, a exceção parecerá ter se originado do seu, throw exenquanto que com o último, será originada corretamente da throwdeclaração original .
um CVn

2
Por que você conecta o Application.ThreadExceptionevento e quebra todas as exceções com um catch(Exception ex) {ex.Log(ex);}. Eu provavelmente concordaria que a primeira é uma prática excelente, mas a segunda acrescenta o risco de duplicar os logs de erros e oculta a ocorrência da exceção. Também throw exé muito, muito ruim.
21413 Keith

1
Eu entendi sobre catch (Exception ex) {throw ex; sendo inútil. Portanto, suponho que "redundante" não seja a melhor palavra para afirmar "Não faça isso". Por isso, mudei um pouco o post para afirmar melhor que os dois primeiros exemplos de try catch devem ser evitados.
Larry

3
Resposta ótima e construtiva, acima de tudo, gostei da frase Somente ar :) E obrigado pelo Application.ThreadExceptionevento, eu não estava ciente disso, muito útil.
Mahdi Tahsildari


61

A prática recomendada é que o tratamento de exceções nunca oculte problemas . Isso significa que os try-catchblocos devem ser extremamente raros.

Existem três circunstâncias em que usar um try-catchfaz sentido.

  1. Sempre lide com exceções conhecidas o mais baixo possível. No entanto, se você espera uma exceção, geralmente é uma prática melhor testá-la primeiro. Por exemplo, análise, formatação e exceções aritméticas são quase sempre melhor tratadas por verificações lógicas primeiro, do que por uma específica try-catch.

  2. Se você precisar fazer algo em uma exceção (por exemplo, registrar ou reverter uma transação), emita novamente a exceção.

  3. Sempre lide com exceções desconhecidas o mais alto possível - o único código que deve consumir uma exceção e não repeti-la deve ser a interface do usuário ou a API pública.

Suponha que você esteja se conectando a uma API remota. Aqui, você espera alguns erros (e tem algumas coisas nessas circunstâncias); portanto, este é o caso 1:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

Observe que nenhuma outra exceção é capturada, pois não é esperada.

Agora, suponha que você esteja tentando salvar algo no banco de dados. Temos que reverter isso se falhar, então temos o caso 2:

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

Observe que lançamos novamente a exceção - o código mais alto ainda precisa saber que algo falhou.

Finalmente, temos a interface do usuário - aqui não queremos exceções completamente não tratadas, mas também não queremos ocultá-las. Aqui temos um exemplo do caso 3:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

No entanto, a maioria das estruturas de API ou UI possui maneiras genéricas de executar o caso 3. Por exemplo, o ASP.Net possui uma tela de erro amarela que despeja os detalhes da exceção, mas que pode ser substituída por uma mensagem mais genérica no ambiente de produção. Seguir essas é uma prática recomendada, pois economiza muito código, mas também porque o log e a exibição de erros devem ser decisões de configuração, e não codificadas.

Isso tudo significa que o caso 1 (exceções conhecidas) e o caso 3 (tratamento único da interface do usuário) têm padrões melhores (evite o erro esperado ou o tratamento manual do erro na interface do usuário).

Mesmo o caso 2 pode ser substituído por padrões melhores, por exemplo , escopos de transação (using blocos que revertem qualquer transação não confirmada durante o bloco) tornam mais difícil para os desenvolvedores errar o padrão de boas práticas.

Por exemplo, suponha que você tenha um aplicativo ASP.Net em larga escala. O registro de erros pode ser feito via ELMAH , a exibição de erros pode ser um YSoD informativo localmente e uma boa mensagem localizada em produção. Todas as conexões com o banco de dados podem ser feitas por escopos e usingblocos de transação . Você não precisa de um únicotry-catch bloco.

TL; DR: A melhor prática é realmente não usar try-catchblocos.


4
@Jorj, você deve ler o post inteiro e, se ainda discordar, talvez seja mais construtivo contrariar um dos meus argumentos de apoio, em vez de apenas declarar que você não gosta da minha conclusão. Há quase sempre um padrão melhor do que try-catch- pode (muito ocasionalmente) ser útil e não estou argumentando que você nunca deve usá-los, mas em 99% das vezes há uma maneira melhor.
19413 Keith

De longe, a melhor resposta - quase todos os tipos de desenvolvimento .net têm um HANDLER de algum tipo que é muito mais adequado para lidar com exceções em nível global, facilitando o manuseio consistente das mesmas e facilitando simplesmente o uso. em desenvolvimento (por que alguém iria querer pesquisar em um arquivo de log para rastrear uma pilha ??) @ Quieto, eu lideraria com seu TLDR e adicionaria alguns exemplos dos manipuladores globais (por exemplo, ThreadException, Application_Error, etc.). Por todos os meios pegar erros específicos, mas é louco para embrulhar nunca método em um try / catch / log
b_levitt

34

Uma exceção é um erro de bloqueio .

Antes de tudo, a melhor prática deve ser não lançar exceções para qualquer tipo de erro, a menos que seja um erro de bloqueio .

Se o erro estiver bloqueando , lance a exceção. Uma vez que a exceção já foi lançada, não há necessidade de ocultá-la porque é excepcional; informe o usuário sobre isso (você deve reformatar toda a exceção para algo útil para o usuário na interface do usuário).

Seu trabalho como desenvolvedor de software é tentar evitar um caso excepcional em que algum parâmetro ou situação de tempo de execução possa terminar em uma exceção. Ou seja, as exceções não devem ser silenciadas, mas devem ser evitadas .

Por exemplo, se você souber que alguma entrada inteira pode vir com um formato inválido, use em int.TryParsevez deint.Parse . Existem muitos casos em que você pode fazer isso em vez de apenas dizer "se falhar, basta lançar uma exceção".

Lançar exceções é caro.

Se, afinal, uma exceção é lançada, em vez de gravar a exceção no log depois que ela é lançada, uma das práticas recomendadas é capturá-la em um manipulador de exceção de primeira chance . Por exemplo:

  • ASP.net: Global.asax Application_Error
  • Outros: evento AppDomain.FirstChanceException .

Minha opinião é que as tentativas / capturas locais são mais adequadas para lidar com casos especiais em que você pode converter uma exceção em outra, ou quando você deseja "silenciá-la" para um caso muito, muito, muito, muito, muito especial (um bug na biblioteca lançando uma exceção não relacionada que você precisa silenciar para solucionar o bug inteiro).

Para o restante dos casos:

  • Tente evitar exceções.
  • Se isso não for possível: manipuladores de exceção de primeira chance.
  • Ou use um aspecto PostSharp (AOP).

Respondendo a @thewhiteambit em algum comentário ...

@thewhiteambit disse:

Exceções não são erros fatais, são exceções! Às vezes, eles nem são erros, mas considerá-los erros fatais é uma compreensão completamente falsa do que são exceções.

Primeiro de tudo, como uma exceção não pode ser um erro?

  • Sem conexão com o banco de dados => exceção.
  • Formato de sequência inválido para analisar algum tipo => exceção
  • Tentando analisar JSON e enquanto a entrada não é realmente JSON => exceção
  • Argumento nullenquanto o objeto era esperado => exceção
  • Alguma biblioteca possui um bug => lança uma exceção inesperada
  • Há uma conexão de soquete e ela é desconectada. Então você tenta enviar uma mensagem => exceção
  • ...

Podemos listar 1k casos de quando uma exceção é lançada e, afinal, qualquer um dos casos possíveis será um erro .

Uma exceção é um erro, porque no final do dia é um objeto que coleta informações de diagnóstico - possui uma mensagem e acontece quando algo dá errado.

Ninguém lançaria uma exceção quando não houvesse um caso excepcional. As exceções devem bloquear os erros porque, uma vez lançadas, se você não tentar usar o try / catch e as exceções para implementar o fluxo de controle , significa que seu aplicativo / serviço interromperá a operação que entrou em um caso excepcional .

Além disso, sugiro a todos que verifiquem o paradigma à prova de falhas publicado por Martin Fowler (e escrito por Jim Shore) . Foi assim que eu sempre entendi como lidar com exceções, mesmo antes de chegar a este documento há algum tempo.

[...] considerá-los Erros fatais é uma compreensão completamente falsa do que são exceções.

Geralmente, as exceções cortam algum fluxo de operação e são tratadas para convertê-las em erros compreensíveis pelo homem. Portanto, parece que uma exceção é realmente um paradigma melhor para lidar com casos de erro e trabalhar com eles para evitar uma falha completa do aplicativo / serviço e notificar o usuário / consumidor de que algo deu errado.

Mais respostas sobre preocupações de @whiteambit

Por exemplo, no caso de falta de uma conexão com o banco de dados, o programa pode excepcionalmente continuar gravando em um arquivo local e enviar as alterações ao banco de dados assim que estiver disponível novamente. Sua conversão inválida de String para número pode ser analisada novamente com a interpretação de idioma local em Exception, como quando você tenta o idioma inglês padrão para o Parse ("1,5") falhar e tenta novamente com a interpretação em alemão, que é completamente bom porque usamos vírgula em vez de apontar como separador. Você vê que essas exceções não devem nem estar bloqueando, elas precisam apenas de um tratamento de exceção.

  1. Se seu aplicativo funcionar offline sem persistir os dados no banco de dados, você não deve usar exceções , pois a implementação do fluxo de controle try/catché considerada um antipadrão. O trabalho offline é um possível caso de uso; portanto, você implementa o fluxo de controle para verificar se o banco de dados está acessível ou não, não espere até que ele esteja inacessível .

  2. A análise também é um caso esperado ( não EXCEPCIONAL CASE ). Se você espera isso, não usa exceções para controlar o fluxo! . Você obtém alguns metadados do usuário para saber qual é sua cultura e usa formatadores para isso! O .NET também oferece suporte a esse e outros ambientes, e uma exceção, porque a formatação de números deve ser evitada se você espera um uso específico de cultura do seu aplicativo / serviço .

Uma exceção não tratada geralmente se torna um erro, mas as exceções em si não são codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors

Este artigo é apenas uma opinião ou um ponto de vista do autor.

Como a Wikipedia também pode ser apenas a opinião do (s) autor (es) do artigo, não diria que é o dogma , mas verifique o que o artigo Coding by exception diz em algum lugar de algum parágrafo:

[...] O uso dessas exceções para lidar com erros específicos que surgem para continuar o programa é chamado de codificação por exceção. Esse antipadrão pode degradar rapidamente o software em desempenho e manutenção.

Também diz em algum lugar:

Uso de exceção incorreto

Geralmente, a codificação por exceção pode levar a outros problemas no software com o uso incorreto de exceções. Além de usar o tratamento de exceções para um problema único, o uso incorreto de exceções leva isso adiante, executando o código mesmo depois que a exceção é gerada. Esse método de programação ruim se assemelha ao método goto em muitas linguagens de software, mas ocorre apenas após a detecção de um problema no software.

Honestamente, acredito que o software não pode ser desenvolvido, não levando os casos de uso a sério. Se você sabe disso ...

  • Seu banco de dados pode ficar offline ...
  • Algum arquivo pode ser bloqueado ...
  • Algumas formatações podem não ser suportadas ...
  • Alguma validação de domínio pode falhar ...
  • Seu aplicativo deve funcionar no modo offline ...
  • qualquer que seja o caso de uso ...

... você não usará exceções para isso . Você apoiaria esses casos de uso usando o fluxo de controle regular.

E se algum caso de uso inesperado não for abordado, seu código falhará rapidamente, porque lançará uma exceção . Certo, porque uma exceção é um caso excepcional .

Por outro lado, e finalmente, às vezes você cobre casos excepcionais que lançam exceções esperadas , mas não os lança para implementar o fluxo de controle. Você faz isso porque deseja notificar as camadas superiores que não oferece suporte a algum caso de uso ou que seu código não funciona com alguns argumentos ou dados / propriedades do ambiente.


6

A única vez em que você deve preocupar seus usuários com algo que aconteceu no código é se há algo que eles podem ou precisam fazer para evitar o problema. Se eles puderem alterar dados em um formulário, pressione um botão ou altere a configuração de um aplicativo para evitar o problema e avise-os. Porém, avisos ou erros que o usuário não tem capacidade de evitar apenas os fazem perder a confiança em seu produto.

Exceções e logs são para você, o desenvolvedor, e não o usuário final. Entender a coisa certa a fazer quando você captura cada exceção é muito melhor do que apenas aplicar alguma regra de ouro ou confiar em uma rede de segurança em todo o aplicativo.

A codificação irracional é o ÚNICO tipo de codificação errada. O fato de você achar que algo melhor pode ser feito nessas situações mostra que você está investindo em boa codificação, mas evite tentar estampar alguma regra genérica nessas situações e entenda o motivo de algo ser lançado em primeiro lugar e o que você pode fazer para se recuperar dele.


6

Eu sei que essa é uma pergunta antiga, mas ninguém mencionou o artigo do MSDN aqui, e foi o documento que realmente o esclareceu, o MSDN tem um documento muito bom sobre isso, você deve capturar exceções quando as seguintes condições forem verdadeiras:

  • Você entende bem por que a exceção pode ser lançada e pode implementar uma recuperação específica, como solicitar ao usuário que insira um novo nome de arquivo ao capturar um objeto FileNotFoundException.

  • Você pode criar e lançar uma nova exceção mais específica.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • Você deseja manipular parcialmente uma exceção antes de transmiti-la para manipulação adicional. No exemplo a seguir, um bloco catch é usado para adicionar uma entrada a um log de erros antes de lançar novamente a exceção.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

Sugiro ler a seção inteira " Tratamento de exceções e exceções " e também as práticas recomendadas para exceções .


1

A melhor abordagem é a segunda (aquela na qual você especifica o tipo de exceção). A vantagem disso é que você sabe que esse tipo de exceção pode ocorrer no seu código. Você está lidando com esse tipo de exceção e pode retomar. Se alguma outra exceção surgir, isso significa que algo está errado, o que o ajudará a encontrar erros no seu código. O aplicativo eventualmente trava, mas você saberá que há algo que você perdeu (bug) que precisa ser corrigido.


1

Com exceções, tento o seguinte:

Primeiro, pego tipos especiais de exceções, como divisão por zero, operações de E / S e assim por diante e escrevo código de acordo com isso. Por exemplo, uma divisão por zero, dependendo da proveniência dos valores que eu poderia alertar o usuário (por exemplo, uma calculadora simples em que em um cálculo intermediário (não os argumentos) chega em uma divisão por zero) ou para tratar silenciosamente essa exceção, registrando e continue processando.

Então tento capturar as exceções restantes e registrá-las. Se possível, permita a execução do código, caso contrário, alerte o usuário que ocorreu um erro e peça para ele enviar um relatório de erro.

No código, algo como isto:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}

1
Divida por zero exceções e similares, é melhor lidar com a verificação 0prévia de um numerador, em vez de a try-catch. Também por que pegar o genérico Exceptionaqui? É melhor deixar o erro aparecer do que lidar com ele aqui em todos os casos em que você não o espera.
21413 Keith

Leia melhor o que escrevi sobre o exemplo que dei - observe o "não está nos argumentos". Obviamente, qualquer calculadora deve verificar os argumentos fornecidos. O que eu falei foi sobre os passos intermediários. Nesse ponto, a verificação do argumento do usuário já aconteceu. Também em alguns aplicativos, é melhor evitar exceções para aparecer. Alguns aplicativos devem tratar exceções silenciosamente, enquanto outros devem tratar exceções como erros. Um servidor da Web, por exemplo, deve ser executado mesmo quando houver exceções, onde o software médico (máquinas de raio-x, por exemplo) deve ser interrompido quando ocorrerem exceções.
precisa

Nenhum aplicativo deve sempre tratar exceções em silêncio. Ocasionalmente, há uma exceção que o código pode manipular, mas esse uso deve ser raro e específico à exceção esperada. Seu exemplo de servidor da Web é ruim - ele deve ter definições de configuração que permitam escolher como os erros são registrados e se são exibidos com detalhes ou apenas uma página HTTP 500, mas eles nunca devem ignorar silenciosamente os erros.
Keith

Estou tentando descobrir o que realmente está motivando as pessoas a adicionar mais um sinônimo para "ir". Mas com relação à divisão por zero, esse seria o ÚNICO tipo de exceção que posso justificar o aprimoramento da linguagem. Por quê? Porque pode muito bem ser que A) zero seja estatisticamente infinitesimal em seu conjunto de dados e B) usar (permitir) uma exceção pode ser muito mais eficiente, porque fazer a divisão é uma maneira de testar um divisor zero. Quando A e B são verdadeiros, a execução média do seu programa será mais rápida usando uma exceção e pode até ser menor.
Mike Layton

1

A segunda abordagem é boa.

Se você não deseja mostrar o erro e confundir o usuário do aplicativo, mostrando uma exceção de tempo de execução (ou seja, erro) que não está relacionada a eles, basta registrar o erro e a equipe técnica poderá procurar o problema e resolvê-lo.

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

Eu recomendo que você faça a segunda abordagem para todo o aplicativo.


2
A segunda abordagem não mostra ao usuário que ocorreu um erro - por exemplo, se eles estivessem salvando algo, não saberiam que ele falhou. catchOs blocos sempre devem chamar throwpara exibir a exceção ou retornar algo / exibir algo que informe ao usuário que a ação falhou. Você deseja receber a chamada de suporte quando eles falham em salvar o que quer que seja, seis meses depois, quando tentam recuperá-lo e não conseguem encontrá-lo.
Keith

0

Deixar o bloco de captura em branco é a pior coisa a fazer. Se houver um erro, a melhor maneira de lidar com isso é:

  1. Faça logon no arquivo \ banco de dados etc.
  2. Tente consertá-lo rapidamente (talvez tentando uma maneira alternativa de fazer essa operação)
  3. Se não conseguirmos corrigir isso, notifique o usuário de que há algum erro e, é claro, aborte a operação

0

Para mim, lidar com exceção pode ser visto como regra de negócios. Obviamente, a primeira abordagem é inaceitável. O segundo é melhor e pode ser 100% correto, se o contexto o indicar. Agora, por exemplo, você está desenvolvendo um suplemento do Outlook. Se você adicionar um exceção não tratada, o usuário do Outlook agora poderá conhecê-lo, pois o Outlook não se destruirá por causa de uma falha no plug-in. E você tem dificuldade para descobrir o que deu errado. Portanto, a segunda abordagem, neste caso, para mim, é correta. Além de registrar a exceção, você pode decidir exibir uma mensagem de erro para o usuário - eu a considero uma regra de negócios.


0

A melhor prática é lançar uma exceção quando o erro ocorrer. Porque ocorreu um erro e não deve ser oculto.

Mas na vida real você pode ter várias situações em que deseja ocultar isso

  1. Você confia no componente de terceiros e deseja continuar o programa em caso de erro.
  2. Você tem um caso de negócios que precisa continuar em caso de erro

6
Não. Você não jogue Exception. Sempre. Lance uma subclasse apropriada de Exceptiontudo que você deseja, mas nunca Exceptionporque isso não fornece absolutamente nenhuma informação semântica. Eu não consigo ver um cenário em que faça sentido lançar, Exceptionmas não uma subclasse dele.
um CVn


0

O catchsem argumentos é simplesmente comer a exceção e é inútil. E se ocorrer um erro fatal? Não há como saber o que aconteceu se você usar catch sem argumento.

Uma declaração de captura deve capturar exceções mais específicas, como, FileNotFoundExceptionentão, no final, você deve capturar Exceptionqual capturaria qualquer outra exceção e registrá-las.


Por que ter um general catch(Exception)no final? Se você não está esperando, é sempre recomendável repassar para a próxima camada.
21413 Keith

1
@Keith sim você está certo ... não há nenhum ponto na captura exceções que você não está esperando, mas você pode a exceção geral para fins de exploração madeireira ..
Anirudha

0

Às vezes, você precisa tratar exceções que não dizem nada aos usuários.

Meu jeito é:

  • Para capturar exceções não encontradas no nível do aplicativo (ou seja, em global.asax) para exceções críticas (o aplicativo não pode ser útil). Essas exceções não estou pegando no lugar. Basta registrá-los no nível do aplicativo e deixar o sistema fazer seu trabalho.
  • Pegue "no local" e mostre algumas informações úteis ao usuário (número incorreto digitado, não é possível analisar).
  • Fique atento e não faça nada em problemas marginais como "Vou verificar informações de atualização em segundo plano, mas o serviço não está sendo executado".

Definitivamente, não precisa ser uma prática recomendada. ;-)


0

Eu posso lhe dizer uma coisa:

O snippet nº 1 não é aceitável porque está ignorando a exceção. (está engolindo como se nada tivesse acontecido).

Portanto, não adicione blocos de captura que não façam nada ou apenas repitam.

O bloco catch deve adicionar algum valor. Por exemplo, mensagem de saída para o usuário final ou erro de log.

Não use a exceção para a lógica normal do programa de fluxo. Por exemplo:

por exemplo, validação de entrada. <- Esta não é uma situação excepcional válida; você deve escrever um método IsValid(myInput);para verificar se o item de entrada é válido ou não.

Código de design para evitar exceção. Por exemplo:

int Parse(string input);

Se passarmos um valor que não pode ser analisado para int, esse método lançaria uma exceção, em vez disso, poderíamos escrever algo como isto:

bool TryParse(string input,out int result); <- este método retornaria booleano indicando se a análise foi bem-sucedida.

Talvez isso esteja um pouco fora do escopo desta questão, mas espero que isso ajude você a tomar decisões corretas quando se trata de try {} catch(){}exceções.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.