Search code examples
c#.netidisposable

How many using statements should I use? Is there a limit?


I have noticed that the correct way to open and close connections to a database is with the using statement because it automatically uses the IDisposable interface to release the resources (please correct me otherwise).

Therefore, I decided to use it, but the code started to look a bit wired after 3 nested usages.

Here's some code I was writing, it's an event handler for a button where I use the using statement to create some MySQL related instances that need to be disposed of once I finish the usage. Could you please tell me if I am using it correctly? Thanks in advance.

private void buttonAdicionar_Click(object sender, EventArgs e)
{
    using (MySqlConnection con = new MySqlConnection(Properties.Settings.Default.ConnectionString))
    {
        using (MySqlDataAdapter da = new MySqlDataAdapter())
        {
            using (DataTable dt = new DataTable())
            {
                try
                {
                    using (MySqlCommand cmd = new MySqlCommand("SELECT codigo, descricao, unidMedida, vlUnitario FROM tab_estoque WHERE codBar = @codBar;", con))
                    {
                        cmd.Parameters.Add("@codBar", MySqlDbType.VarChar).Value = this.textBoxCodBarras.Text;

                        con.Open();
                        da.SelectCommand = cmd;
                        da.SelectCommand.ExecuteNonQuery();
                        da.Fill(dt);

                        // Caso haja alguma linha no DataSet ds então existe um produto com o codigo de barra procurado no banco de dados
                        if (dt.Rows.Count == 1)
                        {
                            bool itemIgual = false;
                            int rowIndex = 0;

                            // Passa por todas as linhas do carrinho de compras para verificar se existe outro item igual
                            foreach (DataGridViewRow dgvCarrinhoRow in dataGridViewCarrinho.Rows)
                            {
                                // Verifica se o produto da linha do carrinho de compra é o mesmo do código de barras
                                if (dgvCarrinhoRow.Cells[1].FormattedValue.ToString() == dt.Rows[0][0].ToString())
                                {
                                    // Verifica se estão tentando vender uma certa quantidade de um produto que esteja acima da quantidade do mesmo no estoque
                                    if (this.VerificarSeExcede(Convert.ToInt32(dgvCarrinhoRow.Cells[1].FormattedValue), Convert.ToInt32(dgvCarrinhoRow.Cells[3].FormattedValue) + 1) == 1)
                                    {
                                        // Adiciona mais um na quantidade do item no carrinho de compra
                                        dgvCarrinhoRow.Cells[3].Value = Convert.ToInt32(dgvCarrinhoRow.Cells[3].FormattedValue) + 1;
                                        // Multiplica o VL. ITEM. pela nova quantidade e armazena o resultado em VL. ITEM
                                        dgvCarrinhoRow.Cells[6].Value = String.Format("{0:f}",
                                            (Convert.ToDouble(dgvCarrinhoRow.Cells[3].Value) * Convert.ToDouble(dgvCarrinhoRow.Cells[5].Value)));

                                        // Adiciona o valor do produto ao valor total da venda
                                        this.totalVenda += Convert.ToDouble(dgvCarrinhoRow.Cells[5].Value);
                                    }
                                    else if (this.VerificarSeExcede(Convert.ToInt32(dt.Rows[0][0].ToString()), 1) == 0)
                                    {
                                        MessageBox.Show("Ocorreu a tentativa de vender um produto que está em falta no estoque.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    }
                                    else
                                    {
                                        MessageBox.Show("Ocorreu a tentativa de vender uma certa quantidade deste produto que excede a quantidade do mesmo no estoque.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    }

                                    itemIgual = true; // Evita que o if abaixo seja executado
                                    break; // Sai do loop para econimizar tempo no processamento
                                }

                                rowIndex++;
                            }

                            // Caso o item não seja igual a nenhum outro no carrinho ele é adicionado
                            if (!itemIgual)
                            {
                                // Verifica se estão tentando vender uma certa quantidade de um produto que esteja acima da quantidade do mesmo no estoque
                                if (this.VerificarSeExcede(Convert.ToInt32(dt.Rows[0][0].ToString()), 1) == 1)
                                {
                                    this.dataGridViewCarrinho.Rows.Add(
                                        ++this.item,                     // ITEM
                                        dt.Rows[0][0],    // CÓDIGO
                                        dt.Rows[0][3],    // DESCRIÇÃO
                                        1,                          // QTD.
                                        dt.Rows[0][2],    // UN.
                                        dt.Rows[0][3],    // VL. UNIT.
                                        dt.Rows[0][3]);   // VL. ITEM.

                                    // Adiciona o valor do produto ao valor total da venda
                                    this.totalVenda += Convert.ToDouble(dt.Rows[0][3].ToString());
                                }
                                else if (this.VerificarSeExcede(Convert.ToInt32(dt.Rows[0][0].ToString()), 1) == 0)
                                {
                                    MessageBox.Show("Ocorreu a tentativa de vender um produto que está em falta no estoque.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                }
                                else
                                {
                                    MessageBox.Show("Ocorreu a tentativa de vender uma certa quantidade deste produto que excede a quantidade do mesmo no estoque.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                }
                            }

                            this.AtualizarValorCompra();
                            this.dataGridViewCarrinho.ClearSelection();
                        }
                        else // Mensagem exibida caso a consulta nao retorne alguma coisa
                        {
                            MessageBox.Show("Este item não consta no banco de dados.", "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Ocorreu um erro durante a comunicação com o banco de dados.\n\n" + ex.Message, "Caixa", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
    }

    this.LimparControles(1);
}

Solution

  • There is no set limit to how many levels of nesting you can have, with or without using, but of course there is a practical limit of how much nesting you can fit on screen without making your eyes hurt. To that end, it is often a good idea to limit nesting. You can do it by observing that curly braces after compound statements are optional. Therefore, you can do this:

    using (MySqlConnection con = new MySqlConnection(Properties.Settings.Default.ConnectionString))
    using (MySqlDataAdapter da = new MySqlDataAdapter())
    using (DataTable dt = new DataTable()) {
        ...
    }
    

    The statements remain nested inside each other as before, but they look "flat" on the screen.

    One limitation of this approach is that all three variables (con, da, and dt) will be disposed at the end of the same scope. This is not a problem in this particular case, because you end all three scopes without any statements in between (i.e. you have three closing braces at the end). However, a need to end the scope of one of the variables earlier than others may force you to use an additional level of nesting.