Você está na página 1de 8

Tratamento de excees com C#

No importa o quo correto seja o seu cdigo, seus programas sempre


devem estar preparados para tratar erros. Por exemplo, durante um
processamento complexo seu cdigo pode descobrir que no term
permisso para ler um arquivo, ou enquanto ele est enviando uma
requisio por rede, a conexo de rede pode cair.
Nessas situaes excepcionais, no suficiente que um mtodo retorna
um cdigo de erro pode haver vrios outros pontos do programa
dependentes deste onde o erro ocorreu, ento o que voc realmente
quer que o programa relate o erro para o usurio de forma tranqila e
se recupere do erro para que no trave ou no feche abruptamente. A
linguagem c# possui timas formas de tratar esse tipo de situao
atravs de um mecanismo chamado tratamento de excees (exception
handling).

Classes de excees
Em c#, uma exceo um objeto criado (ou lanado) quando uma
condio particular excepcional de erro ocorre. Esse objeto contm
informaes que podem ajudar a capturar e tratar o problema. Embora
possamos criar nossas prprias classes de excees, o DotNet nos d
muitas classes de excees predefinidas.

Capturando excees
J que o DotNet inclui um leque de classes de excees, como voc
pode us-las para capturar condies de erro em seu cdigo? Para lidar
com possveis condies de erro em seu cdigo c#, voc normalmente
vai dividir a parte relevante do seu programa em blocos de trs tipos
diferentes:

Blocos try que contm cdigo que forma a parte normal das
operaes do programa, mas que podem encontrar algumas
condies srias de erro.

Blocos catch que contm cdigo que lida com as vrias condies
de erro que podem aparecer enquanto o cdigo do bloco try est
sendo processado.

Blocos finally que contm o cdigo que desaloca recursos ou


executa qualquer outra ao ao final de um bloco try ou de um
bloco catch. importante entender que o bloco finally ser
executado independentemente de uma exceo ter sido lanada.
Uma vez que colocamos cdigo de tarefas de finalizao que
julgarmos que sempre deva ser executado no bloco finally, o
bloco finally opcional.

Ento como fazer esses blocos trabalharem juntos para capturar as


condies de erro? Vamos l:
1. O fluxo de execuo entra no bloco try
2. Se nenhum erro ocorrer, a execuo prossegue normalmente pelo
bloco try, e quando chega ao fim desse bloco, o fluxo pula para o
bloco finally (passo 5). Contudo, se um erro ocorre dentro do
bloco try, um objeto de erro lanado e a execuo pula para o
bloco catch imediatamente (prximo passo).
3. A condio de erro tratada no bloco catch.
4. Ao final do bloco catch a execuo vai naturalmente para o bloco
finally.
5. O bloco finally executado.
A sintaxe usada no c# para utilizar os blocos try, catch e finally a
seguinte:
try
{
//cdigo de execuo normal
}
catch
{
//tratamento do erro
}
finally
{
//finalizao
}
Algumas variaes da estrutura acima podem ser:
Omisso do bloco finally
Obteno do objeto de exceo no cdigo catch
Utilizao de vrios blocos catch
Omisso do bloco catch para que haja apenas os blocos try e
finally.

Tudo muito bom, tudo muito bem, mas a pergunta que no quer calar :
se o cdigo est rodando no bloco try, como ele sabe quando saltar para
o bloco catch se um erro ocorre?
Se um erro detectado, o cdigo faz uma coisa que conhecida como
lanamento de uma exceo. Em outras palavras, ele cria um objeto
baseado em uma classe de exceo e o lana, mais ou menos assim:
throw new OverflowException();
Aqui ns
instanciamos
um
objeto
de exceo
da classe
OverflowException. Assim que o computador encontra uma instruo de
lanamento de exceo (throw) dentro de um bloco try, ele
imediatamente procura por um bloco catch associado com o bloco try.
Se houver mais de um bloco catch associado com o bloco try, ele
identifica o bloco catch correto checando que classe de exceo est
associada a que bloco catch.
Por exemplo, quando o objeto do tipo OverflowException lanado, a
execuo salta para o seguinte bloco catch:
catch (OverflowException e)
{
...
}
Em outras palavras, o computador procura pelo bloco catch que indica
um objeto de exceo cuja classe se encaixa com a classe do objeto de
exceo lanado. Pode ser uma a mesma classe ou uma classe base.

Implementando mltiplos blocos catch


A forma mais simples de ver os blocos try...catch...finally funcionando
na prtica com exemplos. No exemplo a seguir pediremos um nmero
ao usurio repetidamente e depois o mostraremos. Contudo, para deixar
o exemplo interessante, vamos imaginar que o nmero tem que estar
entre 0 e 5. Caso contrrio, o programa no processar o nmero
adequadamente. Sendo assim lanaremos uma exceo se o usurio
digitar qualquer coisa que esteja fora desse intervalo.
using System;
namespace TryCatchException
{

public class Teste


{
public static void Main()
{
string userInput;
bool digitou = true;
while (digitou)
{
try
{
Console.Write(Insira um nmero entre 0 e 5
+
(ou pressione Enter para sair);
userInput = Console.ReadLine();
if (userInput == )
{
digitou = false; //quer sair
}
/* aqui pode ser lanada uma exceo de
converso se o usurio digitar texto ao
invs de nmero
*/
int index = Convert.ToInt32(userInput);
if (index < 0 || index > 5)
{
//lanamos uma exceo
throw new IndexOutOfRangeException(
You typed in + userInput);
}
//imprime o nmero
Console.WriteLine(Voc digitou: + index);
} //fim do try
catch (IndexOutOfRangeException e)
{
Console.WriteLine(Exception: +
Nmero deve estar entre 0 e 5. +
e.Message);
} //fim do catch
catch (Exception e)
{
Console.WriteLine(
Ocorreu uma exceo conhecida : +
e.Message);
} //fim do catch
catch
{
Console.WriteLine(Alguma exceo
desconhecida ocorreu.);
} //fim do catch
finally
{
Console.WriteLine(Obrigado.);
}//fim do finally
}//fim do while
}//fim do mtodo Main
}//fim da classe Teste
}//fim do namespace TryCatchException

A parte principal desse cdigo lao de repetio while, que


continuamente utiliza o mtodo Console.ReadLine() para pedir ao
usurio uma nova entrada de valor. Checamos para ver se o usurio
simplesmente apertou Enter porque neste caso, imaginamos que ele
deseja sair do programa.
O mtodo Convert.ReadLine() retorna uma string, ento nossa primeira
tarefa convert-la para um int usando o mtodo Convert.ToInt32().
Neste ponto o compilador pode lanar uma exceo caso o usurio
tenha digitado um valor que no possa ser convertido corretamente
para inteiro.
Observe que colocamos no bloco finally uma mensagem de
agradecimento ao usurio. Isso significa que no importanto se ocorra
uma exceo ou no, no final o usurio receber uma mensagem de
agradecimento.
Embora o compilador esteja atento a excees que possam ocorrer, o
cdigo acima mostra que ns tambm podemos criar condies de
exceo. Ns checamos se o valor convertido para inteiro est dentro do
intervalo entre 0 e 5. Caso no esteja lanamos uma exceo do tipo
IndexOutOfRangeException e passamos como parmetro a mensagem
de erro da exceo.
O DotNet contm muitas classes de exceo que so derivadas da classe
System.Exception. Cada uma delas cuida de um tipo particular de
condio de exceo.
Ao ser lanada uma exceo (seja pelo nosso cdigo ou pelo
compilador), o fluxo de processamento saltar direto para o bloco catch
correspondente a exceo que ocorreu.
Repare que utilizamos trs blocos catch. Um para tratar especificamente
o problema de nmeros que no esto no intervalo entre 0 e 5
(IndexOutOfRangeException). Tambm criamos um para erros genricos
(Exception) para onde a execuo ir, se por exemplo ocorrer um erro
de converso.
Quando utilizamos vrios blocos catch, em geral colocamos primeiro os
tratamentos de excees mais especficas e depois os tratamentos de
excees mais genricas.
Observe que criamos ainda um terceiro bloco catch que no especifica o
tipo de exceo. Esse bloco para o caso em que a exceo ocorrida

no consegue ser tratada por nenhuma classe de exceo do DotNet.


Isso til por exemplo quando um erro de sistema inesperado ocorre,
ou quando utilizamos em nossos programas bibliotecas de linguagens
antigas que embora funcionem no DotNet no so completamente
gerenciveis por ele (como bibliotecas de C++ por exemplo).

Algumas propriedades de um objeto de exceo


No exemplo anterior, utilizamos a propriedade Message do objeto de
exceo. Contudo, existem algumas outras propriedades interessantes
disponveis:
HelpLink: um link para um arquivo de help que d mais informaes
sobre a exceo.
Message: um texto que descreve as condies do erro.
Source: o nome do aplicativo ou objeto que causou a exceo.
StackTrace: D detalhes sobre a chamada de mtodos na pilha (para
ajudar a descobrir em qual mtodo a exceo foi lanada)
TargetSite: um objeto refletido do DotNet que descreve o mtodo que
lanou a exceo.
InnerException: Se a exceo foi lanada de dentro de um bloco catch,
essa propriedade contm o objeto de exceo que enviou o cdigo para
dentro do bloco catch.
Dessas propriedades, StackTrace, TargetSite e InnerException so
dadas automaticamente pelo ambiente de execuo do DotNet enquanto
que as demais (Source, HelpLink e Message) podem ser configuradas
caso voc mesmo crie uma classe de exceo. Por exemplo:
if (ErrorCondition == true)
{
Exception myException = new
ClassmyException(Help!!!!);
myException.Source = My Application Name;
myException.HelpLink = MyHelpFile.txt;
throw myException;
}

Blocos de tratamento aninhados


Uma caracterstica muito interessante das excees que voc pode
aninhar blocos try colocando um dentro do outro. Assim, por exemplo:
try
{
// Ponto A
try
{
// Ponto B
}
catch
{
// Ponto C
}
finally
{
// finalizao
}
// Ponto D
}
catch
{
// tratamento de erro
}
finally
{
// finalizao
}
Vamos entender como isso funciona. Se uma exceo for lanada dentro
do bloco try mais externo mas fora do bloco try mais interno (pontos A e
D), ento a situao de exceo capturada pelo bloco catch mais
externo e o bloco finally mais externo executado. Se uma exceo
lanada dentro do bloco try interno (ponto B), e a exceo ser tratada
pelo bloco catch interno e o bloco finally interno ser executado antes
da execuo continuar o bloco try externo (no ponto D).
E o mais interessante: se ocorrer uma exceo no bloco catch interno
(ponto C), essa exceo ser entendida como se tivesse sido lanada
pelo bloco try mais externo, ento o fluxo de execuo imediatamente
abandonar o bloco catch interno e executar o bloco finally mais
interno, para logo em seguida saltar para o bloco catch externo para o

tratamento dessa exceo. Isso tambm acontece, se a exceo ocorrer


no bloco finally interno, o fluxo de execuo imediatamente desviado
para o bloco catch externo.
Embora ns tenhamos visto uma situao com apenas dois blocos try
aninhados, o mesmo princpio continua valendo no importa quantos
blocos try voc aninhar dentro de outros. A cada estgio, o ambiente de
execuo do DotNet ir transferir suavemente o controle para o bloco
catch mais conveniente.
Blocos aninhados de tratamento de exceo so importantes para:

Modificao do tipo de exceo lanada


Habilidade de tratamento de diferentes tipos de exceo em
diferentes pontos do seu cdigo

O que acontece se uma exceo no for tratada?


Algumas vezes uma exceo pode ser lanada, mas no h bloco catch
em seu cdigo que esteja apto a trat-la. O que acontece ento?
O ambiente de execuo do DotNet ir capturar a exceo. Contudo, os
resultados, nesse caso, no so muito interessantes. A execuo do seu
cdigo ser terminada abruptamente e ser mostrada ao usurio uma
caixa de dilogo com uma reclamao de que o cdigo no tratou
determinada exceo, assim com detalhes sobre a exceo dados pelo
DotNet, os quais o usurio provavelmente no entender.
Por isso, em geral, se voc est criando um programa, voc deve tentar
capturar o mximo de excees que voc puder, e trat-las de forma
conveniente. De uma forma geral, as situaes que costumam gerar
excees so situaes onde se depende de um fator externo para que o
programa funcione como:

Interao com o usurio


Acesso a arquivos
Acesso a banco de dados
Interao com outros computadores atravs de uma rede de
computadores

Você também pode gostar