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 coletor de lixo não consegue limpar automaticamente — identificadores de arquivo, conexões de banco de dados e 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 fornecendo 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 ocorrer uma exceção antes de você chegar a essa linha? A instrução using garante que a limpeza aconteça, mesmo quando as coisas dão errado:
using (FileHandler handler = new FileHandler())
{
// Trabalhe com o handler
} // Dispose() chamado automaticamente aquiO C# moderno oferece uma sintaxe mais limpa com a declaração using, que descarta o objeto quando ele sai do escopo:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Trabalhe com o handler
} // Dispose() é chamado quando o método saiA instrução using funciona com qualquer tipo que implemente IDisposable. Classes integradas, como StreamReader, SqlConnection e HttpClient, todas implementam essa interface, tornando o gerenciamento adequado de recursos simples e confiável.
Desafio
FácilVamos criar um simulador de conexão com 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 implementeIDisposable. Sua conexão deve:- Ter uma propriedade
ConnectionName(string, somente leitura) definida por meio 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 somente se ainda não tiver sido descartada (evitando o descarte duplicado) - Ter um método
Query(string sql)que retorneExecuting on {ConnectionName}: {sql}
- Ter uma propriedade
Program.cs: no 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 (por exemplo,
MainDB) - A consulta SQL a ser executada (por exemplo,
SELECT * FROM Users)
Use uma instrução using para criar sua conexão. Dentro do bloco, chame o método Query e imprima o resultado. Quando o bloco using terminar, Dispose() será chamado automaticamente.
Por exemplo, se as entradas forem MainDB e SELECT * FROM Users, a saída deverá 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 liberados, mesmo que ocorra uma exceção dentro do bloco!
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 um 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étodosPratique por conta própria: Compilador de C# online