Tratamento de exceções (Guia de programação em C#)
Um bloco try é usado por programadores C# para particionar código que pode ser afetado por uma exceção. Os blocos de captura associados são usados para lidar com quaisquer exceções resultantes. Um bloco final contém código que é executado independentemente de uma exceção ser lançada ou não no bloco, como liberar try
recursos alocados try
no bloco. Um try
bloco requer um ou mais blocos associados catch
, ou um finally
bloco, ou ambos.
Os exemplos a seguir mostram uma try-catch
instrução, uma try-finally
instrução e uma try-catch-finally
instrução.
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
// Only catch exceptions that you know how to handle.
// Never catch base class System.Exception without
// rethrowing it at the end of the catch block.
}
try
{
// Code to try goes here.
}
finally
{
// Code to execute after the try block goes here.
}
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
}
finally
{
// Code to execute after the try (and possibly catch) blocks
// goes here.
}
Um try
bloco sem um catch
ou finally
bloco causa um erro de compilador.
Blocos de captura
Um catch
bloco pode especificar o tipo de exceção a capturar. A especificação de tipo é chamada de filtro de exceção. O tipo de exceção deve ser derivado de Exception. Em geral, não especifique Exception como o filtro de exceção, a menos que você saiba como lidar com todas as exceções que possam ser lançadas no try
bloco ou tenha incluído uma throw
instrução no final do bloco catch
.
Vários catch
blocos com diferentes classes de exceção podem ser encadeados. Os catch
blocos são avaliados de cima para baixo em seu código, mas apenas um catch
bloco é executado para cada exceção lançada. O primeiro catch
bloco que especifica o tipo exato ou uma classe base da exceção lançada é executado. Se nenhum catch
bloco especificar uma classe de exceção correspondente, um catch
bloco que não tenha nenhum tipo será selecionado, se um estiver presente na instrução. É importante posicionar catch
os blocos com as classes de exceção mais específicas (ou seja, as mais derivadas) primeiro.
Detete exceções quando as seguintes condições forem verdadeiras:
- Você tem uma boa compreensão do motivo pelo qual a exceção pode ser lançada e pode implementar uma recuperação específica, como solicitar que o usuário insira um novo nome de arquivo quando capturar um FileNotFoundException objeto.
- Você pode criar e lançar uma nova exceção mais específica.
int GetInt(int[] array, int index) { try { return array[index]; } catch (IndexOutOfRangeException e) { throw new ArgumentOutOfRangeException( "Parameter index is out of range.", e); } }
- Você deseja lidar parcialmente com uma exceção antes de passá-la para mais manipulação. No exemplo a seguir, um
catch
bloco é 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 (UnauthorizedAccessException e) { // Call a custom error logging procedure. LogError(e); // Re-throw the error. throw; }
Você também pode especificar filtros de exceção para adicionar uma expressão booleana a uma cláusula catch. Os filtros de exceção indicam que uma cláusula catch específica corresponde apenas quando essa condição for verdadeira. No exemplo a seguir, ambas as cláusulas catch usam a mesma classe de exceção, mas uma condição extra é verificada para criar uma mensagem de erro diferente:
int GetInt(int[] array, int index)
{
try
{
return array[index];
}
catch (IndexOutOfRangeException e) when (index < 0)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be negative.", e);
}
catch (IndexOutOfRangeException e)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be greater than the array size.", e);
}
}
Um filtro de exceção que sempre retorna false
pode ser usado para examinar todas as exceções, mas não processá-las. Um uso típico é registrar exceções:
public class ExceptionFilter
{
public static void Main()
{
try
{
string? s = null;
Console.WriteLine(s.Length);
}
catch (Exception e) when (LogException(e))
{
}
Console.WriteLine("Exception must have been handled");
}
private static bool LogException(Exception e)
{
Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
Console.WriteLine($"\tMessage: {e.Message}");
return false;
}
}
O LogException
método sempre retorna false
, nenhuma catch
cláusula usando esse filtro de exceção corresponde. A cláusula catch pode ser geral, usando System.Exception, e cláusulas posteriores podem processar classes de exceção mais específicas.
Finalmente Blocos
Um finally
bloco permite limpar ações que são executadas em um try
bloco. Se presente, o finally
bloco é executado por último, após o try
bloco e qualquer bloco correspondente catch
. Um finally
bloco sempre é executado, quer uma exceção seja lançada ou um catch
bloco correspondente ao tipo de exceção seja encontrado.
O finally
bloco pode ser usado para liberar recursos como fluxos de arquivos, conexões de banco de dados e identificadores gráficos sem esperar que o coletor de lixo no tempo de execução finalize os objetos.
No exemplo a seguir, o finally
bloco é usado para fechar um arquivo que é aberto no try
bloco . Observe que o estado do identificador de arquivo é verificado antes que o arquivo seja fechado. Se o try
bloco não puder abrir o arquivo, o identificador de arquivo ainda terá o valor null
e o bloco não tentará finally
fechá-lo. Em vez disso, se o arquivo for aberto com êxito no try
bloco , o finally
bloco fechará o arquivo aberto.
FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
file = fileinfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Check for null because OpenWrite might have failed.
file?.Close();
}
Especificação da linguagem C#
Para obter mais informações, consulte Exceptions and The try statement na C# Language Specification. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso do C#.