Card nº 1

C# Memória Avançado

using e IDisposable

Em C#, o gerenciamento de memória é automático para objetos gerenciados, mas recursos não gerenciados (como arquivos, conexões de rede ou ponteiros) precisam ser liberados explicitamente. A interface IDisposable define o método Dispose() para essa finalidade. A instrução using garante que Dispose() seja chamado mesmo se ocorrer uma exceção, evitando vazamentos de recursos.

O padrão using pode ser aplicado de duas formas: a declaração using (a partir do C# 8) e o bloco using. Ambos garantem a chamada a Dispose() ao final do escopo. Além disso, ao implementar IDisposable em classes próprias, é recomendável seguir o Dispose pattern, que inclui um método protected virtual void Dispose(bool disposing) para lidar com recursos gerenciados e não gerenciados, e um finalizador (~Destructor) para liberar recursos não gerenciados caso o usuário esqueça de chamar Dispose().

Neste card, vamos explorar como usar using com recursos que implementam IDisposable, como implementar corretamente o Dispose pattern e por que isso é crucial para a robustez de aplicações que interagem com o sistema operacional.

Pontos-chave

  • IDisposable define o método Dispose() para liberar recursos não gerenciados.
  • A declaração using (C# 8+) ou o bloco using garantem a chamada a Dispose() mesmo com exceções.
  • O Dispose pattern completo inclui Dispose(bool) e um finalizador para recursos não gerenciados.
  • Sempre chame GC.SuppressFinalize(this) no Dispose() para evitar finalização desnecessária.
  • Objetos IDisposable devem ser descartados o mais rápido possível após o uso.
DisposableExample.cs
using System;
using System.IO;

public class ResourceHolder : IDisposable
{
    private FileStream _fileStream;
    private bool _disposed = false;

    public ResourceHolder(string path)
    {
        _fileStream = new FileStream(path, FileMode.OpenOrCreate);
    }

    public void WriteData(byte[] data)
    {
        if (_disposed) throw new ObjectDisposedException(nameof(ResourceHolder));
        _fileStream.Write(data, 0, data.Length);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;
        if (disposing)
        {
            _fileStream?.Dispose();
        }
        _disposed = true;
    }

    ~ResourceHolder()
    {
        Dispose(false);
    }
}

class Program
{
    static void Main()
    {
        using (var holder = new ResourceHolder("test.txt"))
        {
            holder.WriteData(new byte[] { 1, 2, 3 });
        } // Dispose é chamado automaticamente aqui
        Console.WriteLine("Recurso liberado.");
    }
}

Exercícios de hoje

  1. 1
    Fácil

    Usando `using` com `StreamWriter`

    Escreva um programa que cria um StreamWriter para o arquivo "log.txt" e escreve a linha "Hello, World!". Use a declaração using para garantir que o arquivo seja fechado corretamente. Exiba "Arquivo escrito e fechado." no console após o bloco using.

    Resolver
  2. 2
    Médio

    Implementando `IDisposable` com recurso gerenciado

    Crie uma classe Logger que implementa IDisposable. Ela deve ter um construtor que recebe um caminho de arquivo e abre um StreamWriter para escrita. O método Log(string message) escreve a mensagem no arquivo. O método Dispose() deve fechar o StreamWriter. No Main, use a classe dentro de um bloco using para escrever duas mensagens e depois exiba "Log finalizado.".

    Resolver
  3. 3
    Desafio

    Dispose pattern completo com recurso não gerenciado

    Implemente uma classe UnmanagedResourceWrapper que encapsula um recurso não gerenciado simulado (um IntPtr alocado com Marshal.AllocHGlobal). A classe deve seguir o Dispose pattern completo: implementar IDisposable, ter um finalizador, e um método protected virtual void Dispose(bool disposing). O método Dispose() público deve chamar Dispose(true) e GC.SuppressFinalize(this). No Main, crie uma instância dentro de um bloco using, use o recurso e, após o bloco, exiba "Recurso não gerenciado liberado.".

    Resolver

Continue estudando