Exceptions mais comuns

O .NET Framework disponibiliza uma vasta coleção de Exceptions para representar situações adversas causadas por um programa.

Dentre elas as mais comuns de encontrar são:

Exception Quando é criada
System.OutOfMemoryException Alocação de memória com new falha.
System.StackOverflowException Pilha exaurida, geralmente quando alguma chamada recursiva é chamada sem limites.
System.NullReferenceException Objeto contendo um valor null referenciado.
System.TypelnitializationException O construtor gera uma exception e não existe um catch dentro do construtor.
System.InvalidCastException Conversão explícita é inválida.
System.ArrayTypeMismatchException O tipo atribuído ao array é incompatível com o tipo do array.
System.IndexOutOfRangeException Indexação de array fora de faixa: menor que zero ou maior que o máximo possível.
System.MulticastNotSupportedException Erro na execução de chamada de um delegate multicast porque o delegate não tem o tipo de retorno void.
System.ArithmeticException Classe base de outras exceptions como DivideByZeroException e OverflowException.
System.DivideByzeroException Divisão por zero em tipos inteiros.

try/catch/finally

Existe um bloco que contém as funções tanto de tratamento de erro como de finalização. A sintaxe é a seguinte:

Veja um exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
public class EHClass
{
      public static void Main ()
      {
            try
            {
                  Console.WriteLine("Executando o try.");
                  throw new NullReferenceException();
            }
            catch(NullReferenceException e)
            {
                  Console.WriteLine("Capturando a exception 1.");
            }
            catch
            {
                  Console.WriteLine("Capturando a exception 1.");
            }
            finally
            {
                  Console.WriteLine("Executando o finally.");
            }
      }
}

Liberando Recursos

Quando uma exception é disparada, a execução é desviada para a rotina de tratamento e não retorna onde estava. Este comportamento normalmente é desejável, mas existem alguns casos em que um certo fragmento de código deve ser chamado incondicionalmente, quer tenha ou não dado uma exception. Por exemplo, podemos ter alocado memória que deve ser liberada incondicionalmente. Para estes casos, precisamos do “try/finally”. A sintaxe é a seguinte:

1
2
3
4
5
6
7
8
try
{
      i = (int) o;      // Conversão inválida, o tem uma strinq,
}
finally
{
      Console. Write("i = {0}", i);
}

Veja um exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
public class Class1
{
      public static void Main()
      {
            int i = 123;
            string s = "Some string",
            object o = s;
            try
            {
                  i = (int) o;      // Conversão inválida:
                  // o tem uma strinq
            }
            finally
            {
                  Console.Write("i = {0}", i);
            }
      }
}

Criando uma exception

O seu código pode criar uma exception com o comando throw. Normalmente as exceptions são criadas por bibliotecas. Veja um exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
public object Pop()
{
      if (first == null)
            throw new Exception("Can't Pop from an empty Stack.");
      else
      {
            object teme = first.Value;
            first = first.Next;
            return teme;
      }
}
...

O comando throw é usado normalmente junto com as estruturas try/catch, mas isto não é uma regra.

Exceptions

A sintaxe de tratamento é a seguinte:

1
2
3
4
5
6
7
8
try
{
      Comandos que podem gerar exception
}
catch
{
      Tratamento
}

Considere o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
using System;
public class Class1
{
      public static void Main()
       {
            int x = 0;
            int y = 10;
            int z = y / x;
            Console.WriteLine(z);
      }
}

Podemos tratar a exception com o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
public class Class1
{
      public static void Main()
      {
            int x = 0;
            int y = 10;
            try
            {
                  int z = y / x;
                  Console.WriteLine(z);
            }
            catch
             {
                  Console.WriteLine("Exception disparada");
            }
      }
}

As exceptions têm um tipo, na verdade uma classe. As nossas rotinas podem tratar um tipo e todas as classes derivadas deste tipo. Os outros são ignorados. No exemplo a seguir estamos tratando apenas um tipo de exception:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
public class Class1
{
      public static void Main()
      {
            int x = 0;
            int y = 10;
            try
            {
                  int z = y / x;
                  Console.WriteLine(z);
            }
            catch(System.DivideByZeroException)
             {
                  Console.WriteLine("Exception disparada");
            }
      }
}

Caso desejemos manter a exception “viva”, podemos recriá-la com “throw”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
public class Class1
{
      public static void Main()
      {
            int x = 0;
            int y = 10;
            try
            {
                  int z = y / x;
                  Console.WriteLine(z);
            }
            catch(System.DivideByZeroException)
             {
                  Console.WriteLine("Exception disparada");
                  throw;
            }
      }
}

As exceptions são objetos que contém propriedades. Podemos acessá-los declarando um objeto ao “capturar” a exception:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
public class Class1
{
      public static void Main()
      {
            int x = 0;
            int y = 10;
            try
            {
                  int z = y / x;
                  Console.WriteLine(z);
            }
            catch(System.DivideByZeroException E)
             {
                  Console.WriteLine(“Exception disparada:+ E.Source);
            }
      }
}

Tratando Erros

O C# possui um mecanismo muito poderoso para tratamento de erro através de exceptions. Este mecanismo é considerado o mais moderno que existe e é o único existente no C#.

O problema

Em uma estrutura de software em camadas, os erros são detectados pelas camadas mais “baixas” de software. Por exemplo, que um arquivo não existe. Mas quem sabe tratar os erros são as camadas mais “altas”, que controlam a interface do usuário e também a lógica de negócio. Entre estas duas camadas, poderão existir várias camadas intermediárias. Estas camadas intermediárias terão que levar o erro em conta, pelo menos para passá-lo para cima, mesmo que não estejam interessadas em tratá-lo.

A solução

No mecanismo de exceptions, uma rotina só trata os erros quando realmente quiser fazer algo a respeito. Caso o erro não te atinja diretamente, você age como se o erro não existisse. Caso alguma rotina chamada dispare uma exception, esta irá “subir” até que alguém a trate. Caso ninguém a trate, uma rotina da própria biblioteca do C# irá tratá-la. Caso alguém a trate, a exception morre.