【问题标题】:Will putting a "using" statement around a DataReader close it?在 DataReader 周围放置一个“使用”语句会关闭它吗?
【发布时间】:2010-01-28 19:21:02
【问题描述】:

我通常这样写我的DataReader 代码:

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

tryfinally 替换为using 块围绕DataReader 的创建是否安全?我想知道的原因是,在我看到的所有 Microsoft 示例中,它们都使用 using 进行连接,但总是在 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();
    }
}

【问题讨论】:

  • 附带说明,我见过的大多数 MS 示例要么过于复杂,要么没有真正利用很多可用的语言功能。部分原因是他们只是简单地滚动了以前版本中的示例代码,实际上只检查它是否仍然运行。我的猜测是这些代码不是由他们最聪明的人维护的,因为这些代码从不聪明或高效。
  • @NotMe 从示例代码的质量来看,我多年来一直怀疑它是由入门级实习生编写和维护的,而不是实际设计课程的人首先。就像微软乏善可陈的 .NET 文档让我期待SO's new documentation expansion
  • @Cupcake 在我看来不是骗子。这里的一个询问using 块是否会关闭数据读取器,另一个询问是否需要关闭它。不是一回事。
  • @ShadowWizard 说得好。

标签: c# .net ado.net


【解决方案1】:

是的。 using 调用 Dispose。在 SqlDataReader 上调用 Dispose 会关闭它。

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

【讨论】:

    【解决方案2】:

    通常,using() 调用 Dispose(),然后依次调用 close()

    在 DataReader 的情况下,只有在设置了 CommandBehavior.CloseConnection 时才会调用 Close(请参阅本文的 cmets 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() 方法,所以对于这个对象,顺序是 反了。

    【讨论】:

      【解决方案3】:

      与示例 here 不同,我的做法是使用 using 块来连接、命令和读取器。请注意,您可以使用块堆叠嵌套以降低缩进成本。

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

      【讨论】:

        【解决方案4】:

        据我所知,如果 Using 块中发生异常,则仍会对该对象调用 Dispose 方法。我通常对所有一次性对象都有一个 Using 语句,没有 Try..Catch。

        编辑:忘了说对于某些对象,调用 Dispose 会依次为该对象调用 Close。

        【讨论】:

          猜你喜欢
          • 2021-01-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-19
          • 2016-04-23
          • 1970-01-01
          • 1970-01-01
          • 2023-03-16
          相关资源
          最近更新 更多