Clique sobre os tópicos listados abaixo para navegar até o conteúdo desejado.

  1. Bloco try-catch
  2. Capturar mais de uma exceção
  3. Catch com filtro when
  4. Bloco finally
  5. Uso do try-catch
  6. Bloco using

O captura de erros em C#, é feito de forma semelhante a linguagem C++ e Java, utilizando o bloco de teste try-catch, como na sintaxe mostrada abaixo:

Sintaxe
try
{
 //código executado
}
catch( tipo_excecao objeto )
{
 //tratamento de erro
}
Onde
try: possui um corpo de código que será executado
tipo_excecao: tipo de dado da exceção lançada, nativa ou do criada pelo usuário
objeto: objeto que irá armazenar os dados da exceção
catch: bloco de código que será executado caso algum erro ocorra em try

Quando o bloco try é utilizado, as declarações dentro de seu corpo são executadas. Caso algum erro ocorra, uma Exceção(Exception) é gerada, lançada e o fluxo de execução é desviado para o catch.

O bloco catch deve possuir codificação para o tratamento da exceção lançada pelo bloco try. As informações estão contidas no objeto exceção que é passado como argumento.

Exemplo 1
using System;
					
public class Program
{
	public static void Main()
	{
		try
		{
			int b = 0;
			int a = 1/b;
		}
		catch(Exception e) //tratamento genérico
		{
			Console.WriteLine("ocorreu um erro.");
		}
	}
}
Saída
Ocorreu um erro

Caso o uso das informações contidas no objeto não sejam necessárias, podemos omitir o nome desse objeto nao bloco catch como mostrado no exemplo abaixo:

Exemplo 2
using System;
					
public class Program
{
	public static void Main()
	{
		try
		{
			int b = 0;
			int a = 1/b;
		}
		catch(Exception) //tratamento genérico
		{
			Console.WriteLine("ocorreu um erro.");
		}
	}
}
Saída
Ocorreu um erro

Como nossas declarações dentro do bloco try podem lançar diferentes tipos de exceções, é possível capturá-las no bloco catch. Para isso, declaramos um catch para cada tipo de possível exceção.

Sintaxe
try
{
  //omitido
}
catch( tipo_excecao1 objeto1 )
{
 //tratamento
}
catch( tipo_excecao2 objeto2 )
{
 //tratamento
}
catch( tipo_excecao3 objeto3 )
{
 //tratamento
}
Onde
tipo_excecao1..3: tipo de dado da exceção lançada, nativa ou do criada pelo usuário
objeto: objeto que irá armazenar os dados da exceção
Exemplo 3
using System;
public class Program
{
    public static int metodo1()
    {
	    int a=1,b=0;
       	return a/b; //divisão por zero
    }
    public static void metodo2()
    {
        int[] vt = {1,2,3};        
        int v = vt[10]; //elemento não existe
    }
	public static void Main() 
	{
        try
        {
            metodo1();
            metodo2();
        }
        catch(DivideByZeroException e )
        {
            Console.WriteLine(e.Message);
        }
        catch(IndexOutOfRangeException e )
        {
            Console.WriteLine(e.Message);
        }
	}
}
Saída
Attempted to divide by zero.

Os blocos catch devem ser declarados a partir das exceções menos genéricas até mais genéricas. Assim, a exceção lançada no try não é capturada de forma errada.

Exemplo 4
//try omitido
catch(DivideByZeroException e )
{
    //mais específica
    Console.WriteLine("Divisão por zero.");
}
catch(IndexOutOfRangeException e )
{
    //mais específica
}
catch(Exception e )
{
    //mais genérica
}
Saída
-

A linguagem C# permite que seja feito um filtro ao capturarmos uma exceção lançada. Isso é feito utilizando a cláusula when que nos auxilia a filtrar as exceções capturadas.

Sintaxe
try
{
  //omitido
}
catch( tipo_excecao objeto  ) when (condicao)
{
 //tratamento
}
Onde
objeto : nome do objeto que irá armazenar os dados do erro ocorrido
tipo_excecao: tipo de dado da exceção lançada.
condicao: expressão que contém o filtro de exceção
Exemplo 5
using System;
public class Program
{
    public static int metodo1()
    {
	    int a=1,b=0;
       	return a/b;            
    }
    public static void metodo2()
    {
        int[] vt = {1,2,3};        
        int v = vt[10];
    }
	public static void Main() 
	{
        try
        {
            metodo1();
            metodo2();
        }
        catch(Exception ex ) when (ex is IndexOutOfRangeException || ex is DivideByZeroException)
        {
            Console.WriteLine("Ocorreu um erro");
        }
	}
}
Saída
Ocorreu um erro

O bloco finally, que pode ser utilizado em conjunto com try-catch. Quando declarado é executado independente de ocorrer ou não uma exceção no try. Após a execução do try ou catch, ocorrendo ou não uma exceção, o fluxo de execução é desviado para o bloco finally.

Sintaxe
try
{
   //corpo
}
catch( tipo_excecao objeto )
{
   //corpo
}
finally
{
  //corpo
}

O bloco finally, normalmente, é utilizado para liberar recursos como alocação de memória, arquivos físicos, conexão com banco de dados e outros.

No exemplo a seguir, vamos abrir um arquivo utilizando a classe FileStream e o método Open da classe File. Uma exceção será simulada para execução dos blocos catch e finally. Esse bloco irá chamar o método Dispose do objeto FileStream fazendo com que os seus recursos internos sejam liberados.

Exemplo 6
using System;
using System.IO;
using System.Text;

public class Program
{
	public static void Main(string[] args) 
    {
        String path = "123.txt"; 
		FileStream arquivo = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
		
        try 
        {
          //manipulação de arquivo omitida
          throw new Exception("Exception forçada");
        } 
        catch (Exception) 
        {
          //omitido
          Console.WriteLine("Ocorreu um erro ao manipular o arquivo");
        } 
        finally 
        {
          Console.WriteLine("Recursos liberados.");
          arquivo.Dispose();
        }
    }
}
Saída
Ocorreu um erro ao manipular o arquivo
Recursos liberados

O bloco try-catch não deve ser codificado em todos os métodos de uma aplicação. Esse bloco deve ficar em pontos centrais para evitar excessos.

Vamos utilizar um exemplo: uma aplicação Console possui um método principal de entrada Main. Assim, codificamos nossas classes e seus métodos que são invocados pela Main onde devemos centralizar a captura e tratamento de erros, log e exibição de mensagem amigável ao usuário, usando o bloco try-catch-finally:

Exemplo 7
using System;
public class Classe1
{
    public Classe1(){}

    public void metodo1()
    {
        //pode ocorrer uma exceção
		Console.WriteLine("metodo1");
    }
}

public class Classe2
{
	public Classe1 cls1;
	
    public Classe2(Classe1 cls)
	{
		cls1 = cls;
	}

    public void metodo2()
    {
        //pode ocorrer uma exceção
		cls1.metodo1();
		Console.WriteLine("metodo2");
    }
}

public class Program
{
	public static void Main()
	{
		Classe1 cls1 = new();
		Classe2 cls2 = new(cls1);
		
		try
		{		
			cls2.metodo2();
		}
		catch(Exception)
		{
            //log do erro
            //tratamento
			//mensagem para o usuário
			Console.WriteLine("ocorreu um erro.");
		}
		finally
		{
			//liberação de recursos usados
			//Classe1, Classe2
		}
	}
}
Saída
metodo1
metodo2

Caso um método, semelhante a Main que centraliza o tratamento de erros, mas que seja utilizado por outras classes. Esse método deve fazer o tratamento local nos blocos catch e finally e relançar o erro para o escopo em está sendo invocado.

O bloco try-catch não deve ser utilizar para tratamento de entrada de dados do usuário como campos vazios, valores com formato inválidos, por exemplo, que são condições normais de acontecer.

Exemplo 8: uso incorreto
using System;
public class Classe1
{
	public int? codigo;
	public string nome;
}

public class Program
{
	public static void Main()
	{
		Classe1 cls = new();
		try
		{	

			//ENTRADA DO USUÁRIO OMITIDA

			if(cls.codigo == null)
			{
				//lançar exceção: "codigo não preenchido!"
			}
			if(cls.nome == null)
			{
				//lançar exceção: "nome não preenchido!"
			}
		}
		catch(Exception)
		{
            //tratamento
			Console.WriteLine("ocorreu um erro.");
		}
		finally
		{
			//liberação de recursos usados
			//Classe1
		}
	}
}

Não deixe blocos catch vazios, pois podem mascarar erros. Registre as informações do erro em logs ou ou relance a exceção.

  1. 13/08/2025 - revisão 2 - Ajustes: pontuais, sintaxes e objetivos; Adição: 'Uso de try-catch' e catch 'sem-objeto'
  2. 10/10/2024 - revisão 1 - Correções e ajustes pontuais
  3. 18/03/2024 - versão inicial