2010-01-28 8 views
23

solito scrivo il mio codice DataReader in questo modo:Inserendo un'istruzione "using" su un DataReader, si chiude?

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

E 'sicuro di sostituire il try e finally con solo un using blocco intorno creazione 's il DataReader? La ragione per cui mi chiedo è perché in tutti gli esempi Microsoft ho visto che usano un uso per la connessione ma chiamano sempre esplicitamente Close() su DataReader.

è Ecco un esempio da 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

Come nota a margine, la maggior parte degli esempi di MS che ho visto sono troppo complicati o non sfruttano gran parte delle funzionalità linguistiche disponibili. In parte è perché si limitano a passare il codice di esempio dalle versioni precedenti e in realtà controllano solo che funzioni ancora. La mia ipotesi è che questo codice non è mantenuto dal loro più brillante perché il codice non è mai intelligente o efficiente. – NotMe

+0

@NotMe dalla qualità del codice di esempio, ho sospettato * per anni * che è stato scritto e gestito da stagisti entry-level, non dalle persone che hanno effettivamente progettato le classi in primo luogo. Sono cose poco brillanti di Microsoft.Documentazione NET che mi fa pensare alla [nuova espansione della documentazione di SO] (http://meta.stackoverflow.com/questions/303865/warlords-of-documentation-a-proposed-expansion-of-stack-overflow). –

+1

Possibile duplicato di [È necessario chiudere manualmente e smaltire SqlDataReader?] (Http://stackoverflow.com/questions/744051/is-it-necessario-a-manual-close-and-dispose-of-sqldatareader) –

risposta

16

Sì. using chiama Dispose. Chiamare Dispose su SqlDataReader lo chiude.

Questa è pseudo-codice di SqlDataReader raccolte da 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

Tipicamente, using() chiamate Dispose() e che chiama close() a sua volta.

In caso di un DataReader, la chiusura viene chiamata solo quando è impostato CommandBehavior.CloseConnection (vedere i commenti di questo articolo http://weblogs.asp.net/joseguay/archive/2008/07/22/ensure-proper-closure-amp-disposal-of-a-datareader.aspx).

EDIT: This article dice qualcosa di interessante:

Il metodo Close() sul SqlDataReader chiama un metodo InternalClose() , che non richiede Dispose. Si noti che in precedenza abbiamo dichiarato che il modo corretto per fare ciò era avere in attesa. Per renderlo più chiaro, il metodo Dispose() in realtà chiama il metodo Close() , quindi per questo oggetto l'ordine è invertito.

1

Da quello che posso ricordare, se si verifica un'eccezione in un blocco Utilizzo, il metodo Dispose viene ancora chiamato sull'oggetto. Di solito ho un'istruzione Using per tutti gli oggetti usa e getta, senza Try..Catch.

EDIT: Ho dimenticato di dire che per alcuni oggetti, la chiamata a Dispose a sua volta chiama Chiudi per quell'oggetto.

1

differenza dell'esempio here, mia pratica è stata quella di impiegare un blocco utilizzando per la connessione, il comando e il lettore. Si noti che è possibile impilare nidificati usando i blocchi per ridurre il costo di indentazione.

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