Le fait de placer une instruction “using” autour d’un DataReader le ferme-t-il?

J’écris habituellement mon code DataReader comme ceci:

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

Est-il prudent de remplacer l’ try et finally par un simple bloc d’ using autour de la création de DataReader ? La raison pour laquelle je me pose des questions est que, dans tous les exemples Microsoft que j’ai vus, ils utilisent un using pour la connexion mais appellent toujours explicitement Close() sur le DataReader .

Voici un exemple de Récupération de données à l’aide d’un 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.GetSsortingng(1)); } } else { Console.WriteLine("No rows found."); } reader.Close(); } } 

Oui. using appels Dispose. L’appel de Dispose sur SqlDataReader le ferme.

C’est le code-code de SqlDataReader glané de 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(); } } 

Généralement, using() appelle Dispose() et appelle ensuite close() .

Dans le cas d’un DataReader, la fermeture est appelée uniquement lorsque CommandBehavior.CloseConnection est défini (voir les commentaires de cet article http://weblogs.asp.net/joseguay/archive/2008/07/22/ensure-proper-closure-amp -disposal-of-a-datareader.aspx ).

EDIT: Cet article dit quelque chose d’intéressant:

La méthode Close () sur le SqlDataReader appelle une méthode InternalClose (), qui n’appelle pas Dispose. Notez que nous avions précédemment indiqué que la bonne façon de procéder consistait à disposer de votre proche appel. Pour rendre encore plus confuse la méthode Dispose (), elle appelle en fait la méthode Close (); ainsi, pour cet object, l’ordre est inversé.

Contrairement à l’exemple ici , ma pratique a été d’utiliser un bloc d’utilisation pour la connexion, la commande et le lecteur. Notez que vous pouvez emstackr des blocs nesteds pour réduire le coût de l’indentation.

 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.GetSsortingng(1)); } } else { Console.WriteLine("No rows found."); } reader.Close(); } } } 

D’après ce que je peux me rappeler, si une exception se produit dans un bloc Using, la méthode Dispose est toujours appelée sur l’object. J’ai généralement une instruction Using pour tous les objects jetables, sans Try..Catch.

EDIT: oublié de dire que pour certains objects, appeler Dispose appellera à son tour Close pour cet object.