简体   繁体   English

将围绕DataReader放置一个“using”语句关闭吗?

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

I usually write my DataReader code like this: 我经常写这样的DataReader代码:

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? 更换try是否安全, finally只需using DataReader创建的using块? 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 . 我想知道的原因是因为在我看到的所有Microsoft示例中,他们都使用了一个用于连接,但总是在DataReader上显式调用Close()

Heres's an example from Retrieving Data Using a DataReader (ADO.NET) : Heres是使用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. using调用Dispose。 Calling Dispose on SqlDataReader closes it. 在SqlDataReader上调用Dispose会关闭它。

This is psuedo-code of SqlDataReader gleaned from Reflector : 这是从Reflector收集的SqlDataReader的伪代码:

    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. 通常, using()调用Dispose()并依次调用close()

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 ). 对于DataReader,只有在设置了CommandBehavior.CloseConnection时才会调用Close(请参阅本文的评论http://weblogs.asp.net/joseguay/archive/2008/07/22/ensure-proper-closure-amp -disareal-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. SqlDataReader上的Close()方法调用InternalClose()方法,该方法不调用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. 为了使它更令人困惑,Dispose()方法实际上调用了Close()方法,因此对于此对象,顺序是相反的。

From what I can recall, if an exception occurs in a Using block, then the Dispose method is still called on the object. 根据我的记忆,如果在使用块中发生异常,则仍然会在对象上调用Dispose方法。 I usually have a Using statement for all disposable objects, without a Try..Catch. 我通常对所有一次性对象都有一个Using语句,没有Try..Catch。

EDIT: Forgot to say that for some objects, calling Dispose will in turn call Close for that object. 编辑:忘了说对于某些对象,调用Dispose将依次为该对象调用Close。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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