Como executar código de limpeza usando finally
O propósito de uma instrução finally
é garantir que a limpeza necessária de objetos, normalmente objetos que estão mantendo recursos externos, ocorra imediatamente, mesmo que uma exceção seja lançada. Um exemplo dessa limpeza é chamar Close em um FileStream imediatamente após o uso, em vez de esperar que o objeto passe pela coleta de lixo feita pelo Common Language Runtime, da seguinte maneira:
static void CodeWithoutCleanup()
{
FileStream? file = null;
FileInfo fileInfo = new FileInfo("./file.txt");
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
file.Close();
}
Exemplo
Para transformar o código anterior em uma instrução try-catch-finally
, o código de limpeza é separado do código funcional, da seguinte maneira.
static void CodeWithCleanup()
{
FileStream? file = null;
FileInfo? fileInfo = null;
try
{
fileInfo = new FileInfo("./file.txt");
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
}
finally
{
file?.Close();
}
}
Como uma exceção pode ocorrer a qualquer momento no bloco try
antes da chamada OpenWrite()
ou a própria chamada OpenWrite()
poderia falhar, não há garantia de que o arquivo esteja aberto quanto tentarmos fechá-lo. O bloco finally
adiciona uma verificação para checar se o objeto FileStream não é null
antes de chamar o método Close. Sem a verificação de null
, o bloco finally
poderia gerar uma NullReferenceException própria, mas a geração de exceções em blocos finally
deve ser evitada, se possível.
Uma conexão de banco de dados é outra boa candidata a ser fechada em um bloco finally
. Como o número de conexões permitidas para um servidor de banco de dados é, às vezes, limitado, você deve fechar conexões de banco de dados assim que possível. Se uma exceção for gerada antes que você possa fechar a conexão, usar o bloco finally
será melhor do que aguardar a coleta de lixo.