我只是看着使用声明,我一直都知道它的作用,但直到现在还没有尝试使用它,我已经提出了以下代码:
using (SqlCommand cmd = new SqlCommand(reportDataSource, new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year; cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start; cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end; cmd.Connection.Open(); DataSet dset = new DataSet(); new SqlDataAdapter(cmd).Fill(dset); this.gridDataSource.DataSource = dset.Tables[0]; }
这似乎是工作,但有没有因为就在这个任何一点我可以告诉我还需要附上这在try catch块捕捉不可预见的错误,例如SQL服务器停机.我错过了什么吗?
据我目前所知,它只是阻止我关闭和处理cmd,但由于仍需要try catch,因此会有更多行代码.
在进行IO工作时,我编写了预期异常.
SqlConnection conn = null; SqlCommand cmd = null; try { conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString) cmd = new SqlCommand(reportDataSource, conn); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year; cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start; cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end; conn.Open(); //opens connection DataSet dset = new DataSet(); new SqlDataAdapter(cmd).Fill(dset); this.gridDataSource.DataSource = dset.Tables[0]; } catch(Exception ex) { Logger.Log(ex); throw; } finally { if(conn != null) conn.Dispose(); if(cmd != null) cmd.Dispose(); }
编辑:为了明确,我在这里避免使用阻止因为我认为记录这样的情况很重要.经验告诉我,你永远不知道会出现什么样的奇怪异常.记录这种情况可能有助于您检测到死锁,或者发现架构更改会影响您使用少量且经过很少测试的部分代码库或任何其他问题.
编辑2:有人可以说,在这种情况下,一个使用块可以包装一个try/catch,这是完全有效的,在功能上是等效的.这真的归结为偏好.您是否希望以处理自己的处置为代价避免额外的嵌套?或者你是否需要额外的嵌套来进行自动处理.我觉得前者比较清洁,所以我这样做.但是,如果我在我工作的代码库中找到它,我不会重写后者.
编辑3:我真的,真的希望MS创建了一个更明确的using()版本,使其更加直观,真正发生的事情,并在这种情况下给予更多的灵活性.考虑以下虚构代码:
SqlConnection conn = null; SqlCommand cmd = null; using(conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString), cmd = new SqlCommand(reportDataSource, conn) { conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString); cmd = new SqlCommand(reportDataSource, conn); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year; cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start; cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end; cmd.Open(); DataSet dset = new DataSet(); new SqlDataAdapter(cmd).Fill(dset); this.gridDataSource.DataSource = dset.Tables[0]; } catch(Exception ex) { Logger.Log(ex); throw; }
using语句只是在finally中使用Dispose()调用创建一个try/finally.为什么不给开发人员一个统一的处理和异常处理方式?
此代码应如下所示,以确保及时关闭连接.仅关闭命令不会关闭连接:
using (SqlConnection con = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString)) using (SqlCommand cmd = new SqlCommand(reportDataSource, con)) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year; cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start; cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end; cmd.Connection.Open(); DataSet dset = new DataSet(); new SqlDataAdapter(cmd).Fill(dset); this.gridDataSource.DataSource = dset.Tables[0]; }
要回答您的问题,您可以在finally块中执行相同的操作,但这样可以很好地调整代码范围并确保您记得清理.
using
在这种情况下使用语句可能没有任何好处,如果你还是要使用try
/ catch
/ finally
block.如您所知,该using
语句是处理对象的try
/的语法糖.如果你打算拥有自己的/ 无论如何,你当然可以自己做.finally
IDisposable
try
finally
Dispose
这实际上主要归结为风格 - 您的团队可能更熟悉using
语句或using
语句可能使代码看起来更清晰.
但是,如果using
声明隐藏的样板仍然存在,请继续自行处理,如果这是您的偏好.
如果您的代码如下所示:
using (SqlCommand cmd = new SqlCommand(...)) { try { /* call stored procedure */ } catch (SqlException ex) { /* handles the exception. does not rethrow the exception */ } }
然后我会重构它以使用try .. catch ..最后.
SqlCommand cmd = new SqlCommand(...) try { /* call stored procedure */ } catch (SqlException ex) { /* handles the exception and does not ignore it */ } finally { if (cmd!=null) cmd.Dispose(); }
在这种情况下,我将处理异常,所以我别无选择,只能添加try..catch,我不妨放入finally子句并保存自己另一个嵌套级别.请注意,我必须在catch块中执行某些操作,而不仅仅是忽略异常.
在阐述Chris Ballance所说的内容时,C#规范(ECMA-334第4版)第15.13节规定"使用声明被转换为三个部分:获取,使用和处置.资源的使用隐含在try语句中,其中包括finally子句.这个finally子句处理资源.如果获取了null资源,则不会调用Dispose,也不会抛出任何异常."
描述接近2页 - 值得一读.
根据我的经验,SqlConnection/SqlCommand可以通过多种方式生成错误,您几乎需要处理抛出的异常,而不是处理预期的行为.我不确定我是否想在这里使用using子句,因为我希望能够自己处理null资源的情况.