19

SqlConnectionSqlCommand并且SqlDataReader都实现了IDisposable接口。我读到了一个总是包装IDisposables成一个using块的最佳实践。

所以,我查询数据的常见场景看起来像这样(在更大的上下文中,像 linq2sql 这样的映射工具当然是合适的,但假设我们想在这里使用这种方法):

using (SqlConnection cn = new SqlConnection("myConnectionstring"))
{
    using (SqlCommand cm = new SqlCommand("myQuery", cn))
    {
        // maybe add sql parameters
        using (SqlDataReader reader = cm.ExecuteReader())
        {
             // read values from reader object
             return myReadValues;
        }
    }
}

这是正确的方法还是可以被认为是矫枉过正?我对这个级别的嵌套using块有点不确定,但我当然想以正确的方式来做。谢谢!

4

7 回答 7

16

这是100%正确的方法。如果一个类利用IDisposable它应该被包装在一个using语句中以确保该Dispose()方法被调用。此外,不应掉以轻心,与诸如 SQL Server 之类的不受管理的外部技术进行通信。该SqlCommand对象的实现IDisposable是有充分理由的。下面的代码是对象的Dispose()方法SqlCommand

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._cachedMetaData = null;
    }
    base.Dispose(disposing);
}

正如你所看到的,它正在释放对_cachedMetaData对象的引用,以便它也可以被清理。

于 2013-06-07T14:00:21.380 回答
5

您可以使用以下排版方式使代码更靠近左侧:

using (SqlConnection cn = new SqlConnection("myConnectionstring"))
using (SqlCommand cm = new SqlCommand("myQuery", cn))
using (SqlDataReader reader = cm.ExecuteReader())
{
     // read values from reader object
     return myReadValues;
}

正如其他人已经指出的那样,使用三个嵌套using块是正确的。

于 2013-06-07T14:15:52.253 回答
4

这是正确的方法,如果您将与读者一起完成。有时,您需要阅读器保持打开状态(也许您的方法会返回它),因此立即处理阅读器是行不通的。在这些情况下,ExecuteReader 的重载可以帮助您:

var cn = new SqlConnection("myConnectionstring");
var cm = new SqlCommand("myQuery", cn);
var reader = cm.ExecuteReader(CommandBehavior.CloseConnection);
return reader;

这将保持连接和阅读器打开。一旦阅读器关闭/处置,它也将关闭(并处置)连接。

using(var reader = GetReader()) //which includes the code above
{
   ...
} // reader is disposed, and so is the connection.
于 2013-06-07T14:12:20.173 回答
1

是的,这是正确的。您可能会错过嵌套使用中的大括号,因为它们是一个语句,但我认为这不会增加可读性。

于 2013-06-07T14:00:42.923 回答
1

这并不过分。块是一种using很好的做法,因为它可以确保Dispose()调用对象的方法,即使抛出异常也是如此。

不过,这种东西有一个名字。它被称为代码糖。所以:

using (foo bar = new foo()) { //...snip }

是以下的简写代码:

foo bar = null;
Exception error = null;
try {
    bar = new foo();
    // ...snip
}
catch (Exception ex) {
    error = ex;
}
finally {
    if (bar != null) bar.Dispose();
    if (error != null) throw error;
}

任何一种形式都是平等的,它们只是写同一件事的不同方式。换句话说,for和之间while的相同区别:它们基本上做同样的事情,但以不同的方式使用。

using是首选,因为它使代码更短且更具可读性,并为您自动处理。不过,至于你是否应该使用它,不要听那些说你应该总是做某事的人。这是很好的做法,当然,但是知道何时使用为什么使用以及使用或不使用某物的好处和后果比做某事更有价值,因为人们说你应该这样做

编辑:艾伦的回答有一个例子,你不想usingreader.

于 2013-06-07T14:07:51.033 回答
-1

我认为处置SqlCommand. 的SqlConnectionandSqlDataReader应该被处理掉。

因为当SqlConnection它超出范围时它不会自行关闭。

SqlDataReader可以保持忙碌,SqlConnection直到阅读器关闭。

甚至 MSDN 示例都没有处理SqlCommand.

于 2013-06-07T13:59:01.470 回答
-2

我不是专家,但我知道使用被翻译成 try/finally 块也许你可以将 SqlConnection、SqlCommand 和 SqlDataReader 包装成一个独特的 try/finally

try {
     // code here with SqlConnection, SqlCommand and SqlDataReader
}
finally
{
  // Dispose call on SqlConnection, SqlCommand and SqlDataReader
 }
于 2013-06-07T13:59:04.247 回答