在“使用”块中,是否在返回或异常时关闭SqlConnection?


136

第一个问题:
说我有

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();
}

连接是否关闭?因为从技术上讲,我们永远都无法}return以前那样走到最后。

第二个问题:
这次我有:

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*/ }

现在,说出try我们中的某个地方,我们得到了一个错误,它被抓住了。连接仍然关闭吗?再次,因为我们跳过的其余代码,try直接进入catch语句。

我在using工作方式上是否太过线性思考?即,Dispose()当我们离开using示波器时,是否会被简单调用?

Answers:


178
  1. 是。

无论哪种方式,退出using块(通过成功完成或错误退出)时,它都会关闭。

尽管我认为这样组织起来会更好,因为即使要稍后支持它的新维护程序员,也更容易看到将要发生的事情:

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*/ 
    }
}

3
@TrueWill-我同意。我只是将代码移到了一些结构上。
大卫,

10
问题:使用Using语句时,我是否甚至需要断开连接?
Fandango68年

3
另外,如果您使用的是交易,则可以通过try catch在中包含using来显式地.Commit或中的.Rollback交易catch。这既可读性又明确,并且在给定异常类型的情况下允许您进行提交。(conn.Close如果未提交,则事务隐式回滚。)。
克里斯

8
@ Fernando68是的,您仍然需要Open连接。 using仅保证Dispose调用该对象的方法。
juharr 2015年

我在使用块里面有返回ExecuteScalar。当我第二次运行该方法时,它非常快,就像连接已打开一样。为什么第二次这么快?
正面观点

46

两个问题都可以。using语句被编译为try / finally块

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

是相同的

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

编辑:将演员表修复为一次性 http://msdn.microsoft.com/en-us/library/yh598w02.aspx


并非完全如此,但已经足够接近了。确切的差异并不重要。
布赖恩

@Bryan没明白,能否请您说出确切的区别,可以帮助我们进一步
精益求精

哇,那是很久以前的评论了:)我发表评论的第二天,好像在进行编辑。我认为这就是我所想到的。
布赖恩

@Bryan是的,在您发表评论后,我已进行了调整。
瑞安·皮德森

17

这是我的模板。从SQL Server选择数据所需的一切。关闭并处置连接,并捕获连接和执行中的错误。

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();
    }
}

*修订时间:2015-11-09 *
根据NickG的建议;如果括号太多让您烦恼,请像这样格式化...

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();
   }

再说一次,如果您为EA或DayBreak游戏工作,那么您也可以放弃任何换行符,因为这些换行符只适合那些不得不稍后再查看您的代码并且真正在乎的人?我对吗?我的意思是用1行而不是23行表示我是一个更好的程序员,对吗?

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(); }

ew ...好 我把它从系统中取出来,做了一段时间的娱乐。继续。


6
您是否知道可以在不使用大括号的情况下使用语句进行堆栈?删除最后一个花括号,然后将using语句彼此
并排放置

是的先生。谢谢。我知道,但希望我的代码能准确显示正在发生的事情,而无需使用太多其他捷径。值得一提的是最终读者。
ShaneLS 2015年

为什么conn.Close();最后使用?不using言通过处置为你做的?
Fredrick Gauss

我相信现在可以了(自.net 3.5起)。早期对.net 2.0尚不清楚,所以我只是养成了检查和关闭的习惯。
ShaneLS '16

1
“是说1行而不是23行意味着我是一个更好的程序员,对吗?” 我喜欢你:-D
PhilippMüller'31

5

离开使用范围时,处置只会被调用。“使用”的目的是为开发人员提供一种确保资源得到处置的有保证的方法。

MSDN

可以在到达using语句的末尾或引发异常并且控制权在语句结束之前离开语句块时退出using语句。


5

Using围绕所分配的对象生成一个try / finally并Dispose()为您调用。

它免除了您手动创建try / finally块并调用的麻烦 Dispose()


3

在第一个示例中,C#编译器实际上会将using语句转换为以下内容:

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();
}

在函数返回之前,finally语句将始终被调用,因此连接将始终被关闭/处理。

因此,在第二个示例中,代码将编译为以下代码:

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)
{
}

异常将在finally语句中捕获,并关闭连接。外部catch子句不会看到该异常。


1
很好的例子,但我不得不不同意您的最后评论,如果在using块内发生异常,它将在没有任何外部catch的情况下被捕获,实际上我是通过在try / catch块内使用2块编写的来测试的,令我惊讶的是,我收到了来自内部第二个using块的异常错误消息。
WhySoSerious 2014年

1

我在try / catch块中编写了两个using语句,并且可以看到,如果将异常放置在内部using语句中,就像ShaneLS 示例一样,该异常的捕获方式也相同。

     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);
     }

无论将try / catch放在何处,都将捕获异常,而不会出现任何问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.