Se uma determinada classe que está sendo criada possuir referências para outros objetos que são custosos, a boa prática é implementar o padrão Disposable, que nos permite explicitamente descartar estes recursos quando não mais precisamos deles. O padrão Disposable consiste na implementação de uma interface chamada IDisposable, que fornece um método Dispose, que dentro dele você fará toda a limpeza necessária.
Disparar exceções em construtores é algo comum, e que na maioria das vezes representam validações dos parâmetros que são passados à instância da classe que está sendo criada. Um cuidado especial nestes casos, é garantir que você nunca armazene nenhum objeto antes de tais validações, por exemplo:
public class MinhaClasse : IDisposable
{
private IntPtr _ponteiro;
private string _valor;
public MinhaClasse(string valor, IntPtr ponteiro)
{
this._ponteiro = ponteiro;
if (string.IsNullOrEmpty(valor))
throw new ArgumentNullException(“valor”);
this._valor = valor;
}
public void Dispose()
{
if (this._ponteiro != IntPtr.Zero)
this._ponteiro = IntPtr.Zero;
}
~MinhaClasse() { Dispose(); }
}
Ao criar a instância desta classe e definir o parâmetro valor como nulo, repare que antes da validação acontecer, o membro _ponteiro já estará com o valor armazenado. Mesmo que você esteja trabalhando da forma politicamente correta, que é implementando a interface IDisposable para a liberação dos recursos, você tem ainda outros problemas, já que ela não funciona por si só. Sabemos que a implementação desta interface é apenas uma convenção, mas para que a limpeza realmente funcione, o desenvolvedor deverá explicitamente invocar o método Dispose.
Neste caso, envolver a instância em um bloco using (que garante a chamada implícita do Dispose) não resolverá. Como sabemos, o using é açúcar sintático, pois na verdade ele é compilado para blocos try/finally. Se instanciarmos a classe dentro do using, a criação da instância será colocada fora do bloco try, e como a exceção está sendo disparada no construtor, o Dispose não será invocado e, infelizmente, teremos que esperar até o destrutor ser invocado, isso se o tivermos implementado.
Simples, fácil de compreender e extremamente útil.
Obrigado!
Boa dica, obrigado.