在“ using”块中是否有一个 SqlConnection 在返回或异常时关闭?

第一个问题:
就算我有

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的工作方式上思维过于线性?即当我们离开 using作用域时,Dispose()是否仅仅被调用?

193777 次浏览
  1. 是的
  2. 是的。

无论哪种方式,当 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*/
}
}

在第一个示例中,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();
}

最后,语句总是在函数返回之前被调用,因此连接总是被关闭/释放。

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

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 子句不会看到异常。

当您离开使用范围时,将简单地调用 Dispose。“使用”的目的是为开发人员提供一种有保证的方法,以确保资源得到处理。

来自 MSDN:

可以在 using 语句结束时退出,也可以在抛出异常并且控制在语句结束前离开语句块时退出。

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

它省去了手动创建 try/finally 块和调用 Dispose()的麻烦

两个问题都是肯定的。 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

这是我的模板。从 SQL 服务器中选择数据所需的所有内容。连接被关闭并处理,连接和执行中的错误被捕获。

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 游戏工作,你也可以放弃任何换行符,因为这些只是为那些必须回来看你的代码的人准备的,谁真的在乎呢?我说的对吗?我的意思是一行代码而不是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(); }

呼... 好吧,我已经把这些话说出来了我也不想再自娱自乐了,继续吧。

我在一个 尝试抓住块中编写了两个 使用语句,我可以看到,如果异常像 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);
}

无论 尝试抓住放置在哪里,异常都会被捕获而没有问题。