简体   繁体   中英

Will putting a “using” statement around a DataReader close it?

I usually write my DataReader code like this:

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

Is it safe to replace the try and finally with just a using block around the DataReader 's creation? The reason I wonder is because in all the Microsoft examples I've seen they use a using for the connection but always explicitly call Close() on the DataReader .

Heres's an example from 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();
    }
}

Yes. using calls Dispose. Calling Dispose on SqlDataReader closes it.

This is psuedo-code of SqlDataReader gleaned from 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();
        }
    }

Typically, using() calls Dispose() and that calls close() in turn.

In case of a DataReader, the Close is called only when CommandBehavior.CloseConnection is set (see comments of this article http://weblogs.asp.net/joseguay/archive/2008/07/22/ensure-proper-closure-amp-disposal-of-a-datareader.aspx ).

EDIT: This article says something interesting:

The Close() method on the SqlDataReader calls an InternalClose() method, which does not call Dispose. Note that previously we stated the correct way to do this was to have your close call dispose. To make it even more confusing the Dispose() method actually calls the Close() method so for this object the order is reversed.

From what I can recall, if an exception occurs in a Using block, then the Dispose method is still called on the object. I usually have a Using statement for all disposable objects, without a Try..Catch.

EDIT: Forgot to say that for some objects, calling Dispose will in turn call Close for that object.

Unlike the example here , my practice has been to employ a using block for the connection, the command and the reader. Note that you can stack nested using blocks to lower the indentation cost.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM