2010-01-28 59 views
23

我通常寫我DataReader這樣的代碼:將在DataReader周圍放置「using」語句關閉它嗎?

try 
{ 
    dr = cmd.ExecuteReader(CommandBehavior.SingleResult); 
    while (dr.Read()) 
    { 
     // Do stuff 
    } 
} 
finally 
{ 
    if (dr != null) { dr.Close(); } 
} 

是否安全,只有圍繞DataReader的創建using塊替換tryfinally?我想知道的原因是因爲在我看到的所有Microsoft示例中,他們都使用用於連接的方式,但始終在DataReader上明確地調用Close()

繼承人是從 Retrieving Data Using a DataReader (ADO.NET)一個例子:

static void HasRows(SqlConnection connection) 
{ 
    using (connection) 
    { 
     SqlCommand command = new SqlCommand(
      "SELECT CategoryID, CategoryName FROM Categories;", 
      connection); 
     connection.Open(); 

     SqlDataReader reader = command.ExecuteReader(); 

     if (reader.HasRows) 
     { 
      while (reader.Read()) 
      { 
       Console.WriteLine("{0}\t{1}", reader.GetInt32(0), 
        reader.GetString(1)); 
      } 
     } 
     else 
     { 
      Console.WriteLine("No rows found."); 
     } 
     reader.Close(); 
    } 
} 
+1

作爲一個方面說明,我見過的大多數MS示例要麼過於複雜,要麼沒有充分利用可用的大部分語言功能。部分原因是因爲他們只是翻閱了以前版本的示例代碼,並且只是檢查它是否仍然運行。我的猜測是,這段代碼並不是由它們最明亮的代碼維護的,因爲代碼從來不聰明或效率不高。 – NotMe 2010-01-28 19:30:38

+0

@NotMe來自示例代碼的質量,我懷疑*多年以來*它是由入門級實習生編寫和維護的,而不是實際設計類的人。這就像微軟的平淡無奇。.NET文檔,這種類型讓我期待[SO的新文檔擴展](http://meta.stackoverflow.com/questions/303865/warlords-of-documentation-a-proposed-expansion-of-stack-overflow)。 – 2015-10-20 11:05:32

+1

[是否需要手動關閉和處置SqlDataReader?](http://stackoverflow.com/questions/744051/is-it-necessary-to-manually-close-and-dispose-of-sqldatareader) – 2015-10-20 12:02:55

回答

16

是的。 using調用Dispose。在SqlDataReader上調用Dispose關閉它。

這是僞代碼SqlDataReader的從Reflector收集:

public void Dispose() 
    { 
     this.Close(); 
    } 

    public override void Close() 
    { 
     if(!IsClosed) 
      CloseInternal(true); 
    } 

    private void CloseInternal(bool closeReader) 
    { 
     try 
     { 
      // Do some stuff to close the reader itself 
     } 
     catch(Exception ex) 
     { 
      this.Connection.Abort(); 
      throw; 
     } 

     if(this.Connection != null && CommandBehavior.CloseConnection == true) 
     { 
      this.Connection.Close(); 
     } 
    } 
4

通常,using()電話Dispose()並依次調用close()

如果是DataReader,只有在設置了CommandBehavior.CloseConnection時纔會調用Close(請參閱本文的評論http://weblogs.asp.net/joseguay/archive/2008/07/22/ensure-proper-closure-amp-disposal-of-a-datareader.aspx)。

編輯:This article說一些有趣的事情:

在 的Close()方法調用SqlDataReader的一個InternalClose()方法 ,不調用Dispose。 請注意,之前我們陳述了 這樣做的正確方法是讓 關閉呼叫處置。爲使 更令人困惑,Dispose() 方法實際上調用Close() 方法,因此對於此對象,順序爲 。

1

從我記得,如果在使用塊中發生異常,那麼Dispose方法仍然在對象上調用。我通常對所有可丟棄對象都有一個Using語句,沒有Try..Catch。

編輯:忘了說,對於一些對象,調用Dispose將會依次調用Close對象。

1

不同於示例here,我的做法是採用一種使用塊的連接,則命令和讀取器。請注意,您可以使用塊堆疊來降低縮進成本。

static void HasRows(SqlConnection connection) 
{ 
    using (connection) 
    using (SqlCommand command = new SqlCommand(
    "SELECT CategoryID, CategoryName FROM Categories;", 
    connection)) 
    { 
     connection.Open(); 
     using (SqlDataReader reader = command.ExecuteReader()) 
     { 
      if (reader.HasRows) 
      { 
       while (reader.Read()) 
       { 
        Console.WriteLine("{0}\t{1}", reader.GetInt32(0), 
         reader.GetString(1)); 
       } 
      } 
      else 
      { 
       Console.WriteLine("No rows found."); 
      } 
      reader.Close(); 
     } 
    } 
}