C# - Usando Interfaces - II (IDisposable)


Vamos rever o conceito de Interfaces e mostrar como usar algumas interfaces importantes na linguagem C#. Hoje veremos a interface IDisposable.

Continuando a primeira parte do artigo hoje veremos como usar a interface IDisposable.

A interface IDisposable fornece um mecanismo para liberar recursos não gerenciados.

O uso principal dessa interface é para liberar recursos não-gerenciados. O coletor de lixo automaticamente libera a memória alocada para um objeto gerenciado quando esse objeto não é mais usado. No entanto, não é possível prever quando ocorrerá a coleta de lixo. Além disso, o coletor de lixo não tem conhecimento de recursos não gerenciados, como identificadores de janela, ou abrir arquivos e fluxos.

Usamos o método Dispose método desta interface para explicitamente liberar recursos não gerenciados em conjunto com o coletor de lixo. O consumidor de um objeto pode chamar esse método quando o objeto não for mais necessário.

Vejamos como usar essa interface na prática.

Recursos usados:

Usando a interface IDisposable

Neste primeiro exemplo vamos implementar o método Dispose da interface IDisposable para liberar recursos de um objeto não gerenciado.

Criando o projeto Console

Abra o VS 2017 Community e crie um novo projeto do tipo Console Application com o nome UsandoIDisposable

A seguir inclua uma classe chamada GerenciaArquivos no projeto com seguinte código :

using System;
using System.IO;
namespace UsandoIDisposable
{
    class GerenciaArquivos : IDisposable
    {
        FileStream fs;
        public GerenciaArquivos(string caminhoArquivo)
        {
            fs = new FileStream(caminhoArquivo, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        }
        // Metodo para escrever os dados
        public void Write(byte[] dados)
        {
            fs.Write(dados, 0, dados.Length);
        }
        // Implementando o método Dispose para liberar
        // recursos não gerenciados pelo GC
        public void Dispose()
        {
            fs.Close();
        }
    }
}

A classe GerenciaArquivos implementa a interface IDisposable e define o método Dispose onde faz o seguinte:

  1. Fecha o FileStream usado para abrir o arquivo e escrever dados liberando o recurso

Agora vamos usar essa implementação incluindo o código abaixo no método Main() da classe Program :

using System.Text;
namespace UsandoIDisposable
{
    class Program
    {
        static void Main(string[] args)
        {
            // Usando a instrução using 
            // o método Dipose() será chamado depois que 
            // a instrução for finalizada
            using (GerenciaArquivos gerente = new GerenciaArquivos("teste.data"))
            {
                byte[] dados = Encoding.ASCII.GetBytes("Macoratti.net");
                gerente.Write(dados);
            }
        }
    }
}

Neste código criamos uma instância da classe GerenciarArquivos e usamos a instrução using que vai usar o método Dispose() implementado quando a instrução terminar.

Essa implementação é a mais simples possível. Vejamos agora uma implementação mais robusta.

Implementando IDisposable

Inclua um novo projeto na solução anterior chamado UsandoIDisposable2.

A seguir inclua a classe LogWriter que grava em um arquivo de log,  no projeto:

using System;
using System.IO;
namespace UsandoIDisposable2
{
    public class LogWriter
    {
        private StreamWriter m_Stream;
        public LogWriter(string logFile)
        {
            m_Stream = new StreamWriter(logFile, true);
            m_Stream.WriteLine("Iniciando o log às {0}", DateTime.Now);
        }
        public void WriteLine(string message)
        {
            m_Stream.WriteLine(message);
        }
    }
}

Neste código o StreamWriter criado no construtor da classe implementa a interface IDisposable, de forma que podemos chamar o seu método Dispose.

Vamos fazer isso implementando a interface IDisposable na classe LogWriter.

using System;
using System.IO;
namespace UsandoIDisposable2
{
    public class LogWriter : IDisposable
    {
        private StreamWriter m_Stream;
        public LogWriter(string logFile)
        {
            m_Stream = new StreamWriter(logFile, true);
            m_Stream.WriteLine("Iniciando o log às {0}", DateTime.Now);
        }
        public void WriteLine(string message)
        {
            m_Stream.WriteLine(message);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        // booleano para controlar se
        // o método Dispose já foi chamado
 
      private bool m_Disposed = false;

           
// método para controle
        // da liberação dos recursos
        protected virtual void Dispose(bool disposing)
        {
            if (!m_Disposed)
            {
               
if (disposing)
                {
                    m_Stream.Dispose();
                }
                // Liberando recursos não gerenciados
                //informa que os recursos já foram liberados
                m_Disposed = true;
            }
        }

         ~LogWriter()
        {
              Dispose(false);
        }

     }
}

O método Dispose() definido pela interface IDisposable é um invólucro em torno de um método de protegido Dispose(bool disposing) que faz todo o trabalho. Primeiro, ele verifica uma flag para garantir que não estamos liberando o recurso duas vezes.

No método Dispose(), também há uma chamada para GC.SupressFinalize(this). Isso permitirá que o coletor de lixo libere a memória do objeto diretamente quando ele não estiver mais em uso.

Se omitimos esta chamada, o coletor de lixo terá que colocar o objeto no finalizador da classe, o método -LogWriter() ,  em vez de liberá-lo.

Uma vez que o finalizador foi executado (por uma thread em background), o objeto é elegível para coleta de lixo, mas não será coletado até o GC ser executado novamente.

Quando o finalizador é suprimido, o GC pode coletar o objeto na primeira execução.

Voce pode usar de forma bem simples:

using System;
namespace UsandoIDisposable2
{
    class Program
    {
        static void Main(string[] args)
        {
            LogWriter log = new LogWriter("ArquivoLog.txt");
            log.Dispose();
            //ou
            try
            {
                //codigo aqui
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                log.Dispose();
            }
        }
    }
}

Pegue o código do exemplo aqui :  UsandoIDisposable.zip

(disse Jesus) 'Todavia digo-vos a verdade, que vos convém que eu vá; porque, se eu não for, o Consolador não virá a vós; mas, quando eu for, vo-lo enviarei.'
João 16:7

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti