IDisposable e a Instrução using
Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 45 de 70.
Alguns objetos mantêm recursos que o garbage collector não consegue limpar automaticamente - manipuladores de arquivos, conexões de banco de dados, sockets de rede. A interface IDisposable fornece uma maneira padrão de liberar esses recursos quando você terminar de usá-los.
Uma classe implementa IDisposable ao fornecer um método Dispose():
public class FileHandler : IDisposable
{
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Console.WriteLine("Releasing resources...");
disposed = true;
}
}
}Você poderia chamar Dispose() manualmente, mas e se uma exceção ocorrer antes de você chegar a essa linha? A instrução using garante que a limpeza ocorra, mesmo quando as coisas dão errado:
using (FileHandler handler = new FileHandler())
{
// Trabalhe com o manipulador
} // Dispose() chamado automaticamente aquiO C# moderno oferece uma sintaxe mais limpa com a declaração using, que descarta o objeto quando ele sai de escopo:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Trabalhar com o handler
} // Dispose() é chamado quando o método terminaA instrução using funciona com qualquer tipo que implementa IDisposable. Classes integradas como StreamReader, SqlConnection e HttpClient todas implementam essa interface, tornando o gerenciamento de recursos adequado simples e confiável.
Desafio
FácilVamos construir um simulador de conexão de banco de dados que demonstra o gerenciamento adequado de recursos usando a interface IDisposable e a instrução using. Você criará uma classe que rastreia quando as conexões são abertas e fechadas, garantindo que os recursos sejam sempre liberados corretamente.
Você organizará seu código em dois arquivos:
DatabaseConnection.cs: Crie uma classeDatabaseConnectionno namespaceDataAccessque implementaIDisposable. Sua conexão deve:- Ter uma propriedade
ConnectionName(string, somente leitura) definida através do construtor - Rastrear se a conexão foi descartada usando um campo booleano privado
- Imprimir
Connection opened: {ConnectionName}quando o objeto for criado (no construtor) - Implementar o método
Dispose()para imprimirConnection closed: {ConnectionName}- mas apenas se ainda não tiver sido descartado (evitando o descarte duplo) - Ter um método
Query(string sql)que retornaExecuting on {ConnectionName}: {sql}
- Ter uma propriedade
Program.cs: Em seu arquivo principal, demonstre o gerenciamento adequado de recursos usando a instruçãousingcom sua conexão de banco de dados. Crie uma conexão, execute uma consulta e deixe o blocousingcuidar da limpeza automaticamente.
Você receberá duas entradas:
- O nome da conexão (ex:
MainDB) - A consulta SQL a ser executada (ex:
SELECT * FROM Users)
Use uma instrução using para criar sua conexão. Dentro do bloco, chame o método Query e imprima seu resultado. Quando o bloco using terminar, o Dispose() será chamado automaticamente.
Por exemplo, se as entradas forem MainDB e SELECT * FROM Users, a saída deve ser:
Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDBObserve como a conexão é fechada automaticamente quando o bloco using termina - você nunca precisa se lembrar de chamar Dispose() manualmente. Esse padrão garante que os recursos sejam sempre limpos, mesmo que ocorra uma exceção dentro do bloco!
Folha de consulta
A interface IDisposable fornece uma maneira padrão de liberar recursos que o coletor de lixo não pode limpar automaticamente (manipuladores de arquivos, conexões de banco de dados, sockets de rede).
Uma classe implementa IDisposable fornecendo um método Dispose():
public class FileHandler : IDisposable
{
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Console.WriteLine("Releasing resources...");
disposed = true;
}
}
}A instrução using garante que a limpeza ocorra automaticamente, mesmo quando ocorrem exceções:
using (FileHandler handler = new FileHandler())
{
// Trabalha com o handler
} // Dispose() chamado automaticamente aquiO C# moderno oferece uma sintaxe mais limpa com a declaração using:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Trabalha com o handler
} // Dispose() chamado quando o método terminaA instrução using funciona com qualquer tipo que implemente IDisposable, incluindo classes integradas como StreamReader, SqlConnection e HttpClient.
Experimente você mesmo
using System;
using DataAccess;
class Program
{
public static void Main(string[] args)
{
string connectionName = Console.ReadLine();
string sqlQuery = Console.ReadLine();
// TODO: Use uma instrução 'using' para criar uma DatabaseConnection
// Dentro do bloco using:
// 1. Chame o método Query com o sqlQuery
// 2. Imprima o resultado do método Query
// O método Dispose será chamado automaticamente quando o bloco using terminar
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosNamespaces e DiretivasIntrodução a Classes e ObjetosA Palavra-chave 'this'Métodos e ParâmetrosCampos vs PropriedadesConstrutoresInicializadores de ObjetosRecapitulação - Calculadora Simples4Herança
Sintaxe Básica de Herança (:)A Palavra-chave 'base'Palavras-chave Virtual e OverrideClasses SeladasA Classe Base 'object'Recapitulação - Hierarquia de Funcionários7Recursos Avançados
Sobrecarga de OperadoresIndexadores (this[])Sobrescrita de ToString()Métodos de ExtensãoRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoSingleton Thread-SafePadrão FactoryPadrão Observer (Eventos)Padrão Strategy2Propriedades e Membros Estáticos
Propriedades AutoimplementadasPropriedades de Apenas Leitura/EscritaCampos e Métodos EstáticosClasses EstáticasMembros com Corpo de Expressão5Polimorfismo e Interfaces
Polimorfismo: Compilação vs ExecuçãoInterface vs Classe AbstrataMúltiplas InterfacesInterfaces ExplícitasUpcasting e DowncastingRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição sobre HerançaGenerics (Classes e Métodos)Delegates e EventosAtributos e ReflectionIDisposable e a Instrução usingFundamentos de Injeção de Dependência11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Arquitetura de Classes
Dados de Instância vs EstáticosPalavras-chave 'readonly' e 'const'Campos de SuporteRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Modificadores de AcessoPropriedades para EncapsulamentoImplementação de Ocultação de DadosPadrões de ImutabilidadeRecapitulação - Registros de Estudantes9Argumentos Variáveis
A Palavra-chave 'params'Parâmetros OpcionaisArgumentos NomeadosSobrecarga de Métodos