C# -  Instrução Using : Close e Dispose


Neste artigo vamos recordar o bloco de instrução using e como se comportam os métodos Close e Dispose neste contexto.

O .Net Framework fornece gerenciamento de recursos para objetos gerenciados por meio do coletor de lixo - GC. Você não precisa alocar e liberar explicitamente a memória para objetos gerenciados. Já as operações de limpeza para quaisquer recursos não gerenciados devem ser executadas no destruidor no código C#.

Para permitir que o programador execute explicitamente essas atividades de limpeza, os objetos podem fornecer um método Dispose que pode ser chamado quando o objeto não for mais necessário.

A instrução using define um limite para o objeto fora do qual, o objeto é destruído automaticamente. A instrução using é encerrada ao final do bloco de instruções "using" ou quando a execução sai do bloco indiretamente, por exemplo - quando uma exceção for lançada.

Além disso, a instrução "using" permite especificar vários recursos em uma única instrução. O objeto também pode ser criado fora da instrução "using".

Nota: Os objetos especificados no bloco using devem implementar a interface IDisposable.

O Framework chama o método Dispose dos objetos especificados na instrução "using" quando o bloco é encerrado.

Assim, de forma mais simples, a instrução using é usada para usar recursos e ter a certeza que estes recursos serão liberados no fim do bloco da instrução using.

A seguir temos um exemplo básico de utilização da instrução using para acesso a dados com ADO .NET:

using (SqlConnection conn = new SqlConnection(dsn))

using (SqlCommand cmd = new SqlCommand("SELECT * FROM Clientes", conn))
{

  conn.Open();
  using (SqlDataReader rdr = cmd.ExecuteReader())
  {

   while (rdr.Read())
      Console.WriteLine(rdr[0]);
  }
}

Aqui usamos a instrução using para os objetos SqlConnection, SqlCommand e SqlDataReader e eles serão liberados da memória após o fim do bloco da instrução using.

Agora vejamos um exemplo de código que não usa a instrução using em um projeto do tipo Console .NET Core onde acessamos a tabela Categories do banco de dados Northwind :

No método Main() :

        static void Main(string[] args)
        {
            SemUsarUsing();
            Console.ReadKey();
        }

Método criado sem usar a instrução using:

        private static void SemUsarUsing()
        {
            string texto = "";
            string sConnString = "Data Source=Macoratti;Initial Catalog=Northwind;Integrated Security=True";
            string sSql = "SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryName";

            SqlConnection cn = null;
            SqlCommand cmd = null;
            SqlDataReader rdr = null;
            try
            {
                cn = new SqlConnection(sConnString);
                cmd = new SqlCommand(sSql, cn);
                cn.Open();
                rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    texto += rdr["CategoryName"].ToString() + Environment.NewLine;
                }
                Console.WriteLine(texto);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if ((rdr != null) && (!rdr.IsClosed))
                    rdr.Close();
                if (cmd != null)
                    cmd.Dispose();
                if (cn != null)
                    cn.Dispose();
            }
        }

Embora esse código funcione ele é muito verboso e sujeito a erros. Note que no bloco finally foi mplementado o código para liberar os recursos usados pelos objetos ADO .NET.

A seguir temos o resultado da execução do código acima:

Vamos otimizar o código com a utilização da instrução using. Veja abaixo como ficou:

        private static void UsandoUsing()
        {
            string texto = "";
            string sConnString = "Data Source=Macoratti;Initial Catalog=Northwind;Integrated Security=True";
            string sSql = "SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryName";
            try
            {
                using (SqlConnection cn = new SqlConnection(sConnString))
                {
                    using (SqlCommand cmd = new SqlCommand(sSql, cn))
                    {
                        cn.Open();
                        using (SqlDataReader rdr = cmd.ExecuteReader())
                        {
                            while (rdr.Read())
                            {
                                texto += rdr["CategoryName"].ToString() + Environment.NewLine;
                            }
                            Console.WriteLine(texto);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

Como vemos o código ficou mais enxuto e limpo e fácil de ler, e,  não precisamos usar o bloco finally para liberar os objetos usados pois ao usar o bloco de instrução using os objetos usados serão automaticamente liberados e a conexão encerrada.

Agora atente para o fato de que qualquer coisa declarada na instrução using somente pode ser acessada apenas dentro do seu bloco. Se você quiser fazer referência a variáveis ou objetos fora da instrução using (ou bloco try), tem que declará-los antes de iniciar a instrução.

Então usamos a instrução using pois ela chama o método 'dispose' internamente, sempre que qualquer exceção ocorrer.

Assim todo o tipo que implementa IDisposable em um bloco using terá os recursos liberados da memória sem precisar esperar o coletor de lixo.

E estamos conversados...

"Bendito seja o Deus e Pai de nosso Senhor Jesus Cristo, o Pai das misericórdias e o Deus de toda a consolação;
Que nos consola em toda a nossa tribulação, para que também possamos consolar os que estiverem em alguma tribulação, com a consolação com que nós mesmos somos consolados por Deus."
2 Coríntios 1:3,4

 

Referências:


José Carlos Macoratti