¿en un bloque "using" se cierra una conexión SqlConnection en retorno o excepción?


Primera pregunta:
Digamos que tengo

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}

¿Se cierra la conexión? Porque técnicamente nunca llegamos a la última } como return antes de ella.

Segunda pregunta:
Esta vez tengo:

try
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        int employeeID = findEmployeeID();

        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();
    }
}
catch (Exception) { /*Handle error*/ }

Ahora, digamos que en algún lugar del try obtenemos un error y queda atrapado. ¿La conexión todavía se cierra? Porque de nuevo, saltamos el resto del código en el try y vamos directamente a la instrucción catch.

Estoy pensando ¿demasiado linealmente en cómo funciona using? es decir, ¿Dispose() simplemente se llama cuando dejamos el ámbito using?

Author: jball, 2011-01-17

7 answers

  1. Sí.

De cualquier manera, cuando el bloque using sale (ya sea por finalización exitosa o por error) se cierra.

Aunque creo que sería mejor organizar así porque es mucho más fácil ver lo que va a pasar, incluso para el nuevo programador de mantenimiento que lo soportará más adelante:

using (SqlConnection connection = new SqlConnection(connectionString)) 
{    
  int employeeID = findEmployeeID();    
  try    
  {

            connection.Open();
            SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
            command.CommandTimeout = 5;

            command.ExecuteNonQuery();    
   } 
   catch (Exception) 
   { 
      /*Handle error*/ 
   }

}
 163
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-20 21:30:32

Sí a ambas preguntas. La instrucción using se compila en un bloque try/finally

using (SqlConnection connection = new SqlConnection(connectionString))
{
}

Es lo mismo que

SqlConnection connection = null;
try
{
    connection = new SqlConnection(connectionString);
}
finally
{
   if(connection != null)
        ((IDisposable)connection).Dispose();
}

Editar: Fijar la escayola a Desechable http://msdn.microsoft.com/en-us/library/yh598w02.aspx

 40
Author: Ryan Pedersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-18 15:52:16

Aquí está mi Plantilla. Todo lo que necesita para seleccionar datos de un servidor SQL. La conexión se cierra y se elimina y se detectan errores en la conexión y la ejecución.

string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = @"
    SELECT TOP 1 Person
    FROM CorporateOffice
    WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
    ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
    using (SqlCommand comm = new SqlCommand(selectStatement, conn))
    {
        try
        {
            conn.Open();
            using (SqlDataReader dr = comm.ExecuteReader())
            {
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        Console.WriteLine(dr["Person"].ToString());
                    }
                }
                else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
            }
        }
        catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
        if (conn.State == System.Data.ConnectionState.Open) conn.Close();
    }
}

* Revisadas: 2015-11-09 *
Como sugiere NickG; Si demasiados frenos te molestan, formatea así...

using (SqlConnection conn = new SqlConnection(connString))
   using (SqlCommand comm = new SqlCommand(selectStatement, conn))
   {
      try
      {
         conn.Open();
         using (SqlDataReader dr = comm.ExecuteReader())
            if (dr.HasRows)
               while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
            else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
      }
      catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
      if (conn.State == System.Data.ConnectionState.Open) conn.Close();
   }

Por otra parte, si trabajas para EA o DayBreak games, también puedes renunciar a cualquier salto de línea porque son solo para las personas que tienen que volver y mirar tu código más tarde, ¿y a quién le importa? ¿Tengo razón? Quiero decir 1 línea en lugar de 23 significa que soy un mejor programador, ¿verdad?

using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }

Uf... OK. Lo saqué de mi sistema y he terminado de divertirme por un tiempo. Continúa.

 12
Author: ShaneLS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-21 20:37:28

Dispose simplemente se llama al salir del ámbito de uso. La intención de" usar " es dar a los desarrolladores una forma garantizada de asegurarse de que los recursos se eliminen.

De MSDN :

Una sentencia using puede salir cuando se alcanza el final de la sentencia using o si se lanza una excepción y control abandona el bloque de sentencia antes del final de la sentencia.

 5
Author: overstood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-17 21:02:07

Using genera un try / finally alrededor del objeto que se está asignando y llama Dispose() para usted.

Te ahorra la molestia de crear manualmente el bloque try / finally y llamar a Dispose()

 4
Author: VoodooChild,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-17 21:03:09

En su primer ejemplo, el compilador de C # traducirá la instrucción using a lo siguiente:

SqlConnection connection = new SqlConnection(connectionString));

try
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}
finally
{
    connection.Dispose();
}

Finalmente declaraciones siempre llama antes de que una función devuelve y así, la conexión será siempre cerrado/eliminados.

Por lo tanto, en su segundo ejemplo, el código se compilará de la siguiente manera:

try
{
    try
    {
        connection.Open();

        string storedProc = "GetData";
        SqlCommand command = new SqlCommand(storedProc, connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

        return (byte[])command.ExecuteScalar();
    }
    finally
    {
        connection.Dispose();
    }
}
catch (Exception)
{
}

La excepción quedará atrapada en la sentencia finally y la conexión se cerrará. La excepción no se verá en la cláusula de captura exterior.

 2
Author: Kerri Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-17 21:14:58

Escribí dos usando instrucciones dentro de un probar / atrapar block y pude ver que la excepción estaba siendo atrapada de la misma manera si se coloca dentro de la interior usando sentencia al igual que ShaneLS ejemplo.

     try
     {
       using (var con = new SqlConnection(@"Data Source=..."))
       {
         var cad = "INSERT INTO table VALUES (@r1,@r2,@r3)";

         using (var insertCommand = new SqlCommand(cad, con))
         {
           insertCommand.Parameters.AddWithValue("@r1", atxt);
           insertCommand.Parameters.AddWithValue("@r2", btxt);
           insertCommand.Parameters.AddWithValue("@r3", ctxt);
           con.Open();
           insertCommand.ExecuteNonQuery();
         }
       }
     }
     catch (Exception ex)
     {
       MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
     }

No importa dónde está el probar / atrapar colocado, la excepción será capturada sin problemas.

 1
Author: WhySoSerious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:30