【问题标题】:Trying to understand the 'using' statement better试图更好地理解“使用”语句
【发布时间】:2011-12-29 07:27:16
【问题描述】:

我已经阅读了几篇关于 using 语句的文章,试图了解何时应该使用它。听起来大多数人都认为应该尽可能多地使用它,因为它可以保证处置未使用的对象。

问题是所有示例总是显示如下内容:

using (SqlCommand scmFetch = new SqlCommand())
{
    // code
}

这是有道理的,但它只是一小段代码。对数据库执行查询时应该怎么做?全部步骤是什么?它看起来像这样吗:

string sQuery = @"
    SELECT [ID], [Description]
    FROM [Zones]
    ORDER BY [Description] ";

DataTable dtZones = new DataTable("Zones");

using (SqlConnection scnFetchZones = new SqlConnection())
{
    scnFetchZones.ConnectionString = __sConnectionString;
    scnFetchZones.Open();

    using (SqlCommand scmdFetchZones = new SqlCommand())
    {
        scmdFetchZones.Connection = scnFetchZones;
        scmdFetchZones.CommandText = sQuery;

        using (SqlDataAdapter sdaFetch = new SqlDataAdapter())
        {
            sdaFetch.SelectCommand = scmdFetchZones;
            sdaFetch.Fill(dtZones);
        }
    }

    if (scnFetchZones.State == ConnectionState.Open)
        scnFetchZones.Close();
}

我想知道的是:
• 是否可以嵌套使用 4、5、10 个 using 语句来确保所有对象都被释放?
• 我在什么时候做错了,我应该考虑修改吗?
• 如果由于嵌套 using 语句过多而需要修订,我有哪些选择?

您最终可能会得到一个强大的层次结构,但您的代码应该非常高效,对吧?还是应该只将 SqlDataAdapter 对象放在 using 语句中,并且它会以某种方式确保所有其他对象也被释放?

谢谢。

【问题讨论】:

    标签: c# using-statement


    【解决方案1】:

    嵌套多个 using 语句是完全有效的:

    using(A a = new A())
    using(B b = new B())
    {
       a.SomeMethod(b);
    }
    

    【讨论】:

    • 我喜欢这种语法。我假设ab 将在using 语句的末尾进行处理。
    【解决方案2】:

    如果你对你使用的每个 IDisposable 都使用 using,你永远不会错。使用的嵌套 using 块的数量没有限制。

    【讨论】:

    • 我很想知道你不应该在哪里使用它(而不是不能使用它或不需要)。
    • @GeorgeDuckett,只是当您不想处理有问题的对象时。例如,当使用 BeginExecuteReader 对数据库进行异步查询时...
    • @Lucero 我也避免在使用 WCF 代理客户端时使用语句。如果服务器上发生错误,则 using 语句会尝试处理处于故障状态的客户端,这会吞下异常。我使用手动尝试 {} finally {检查服务状态并关闭相应的服务}
    【解决方案3】:

    就个人而言,我已经多次使用了至少 3 层(连接、命令、其他),我认为它绝对没有问题,但正如您已经暗示的那样,最终会出现可读性问题。与其他嵌套结构一样,您可能需要平衡效率和可维护性。也就是说,您不一定要牺牲效率,但通常有“不止一种方法可以剥猫皮”。

    也就是说,您将很难生成 10 个嵌套层!

    【讨论】:

      【解决方案4】:

      深度没有限制,所以这不是问题。您应该验证 using 的对象是否实现了 IDisposable。并且正在处置的对象不会处置与其连接的所有对象,只会处置它创建的对象。

      那么,你在什么时候做错了:没有限制,但通常它相当浅,你创建对象,执行任务,然后释放对象。如果你做得很深,我会看设计。我认为你很难做到超过几层的深度。

      至于您的重新设计选项,这实际上取决于您在做什么,但您可以将同一个对象用于多个任务。您很可能最终会将任务分解为一个函数(传入任何需要的周围对象)。

      【讨论】:

        【解决方案5】:

        恕我直言,您需要问自己的是:有哪些替代方案?尝试/最终阻止?它们更具可读性吗?更易维护?在几乎所有情况下,答案都是“不”。

        所以使用using。这是 C# 最接近 C++ 的 RAII 模式的东西,一切都很好:-)

        【讨论】:

          【解决方案6】:

          Using 语句是 C# 的语法糖。

          所以下面的代码:

          using(var someDisposableObject = new someDisposableObject())
          {
              // Do Something
          }
          

          实际上是这样的:

          var someDisposableObject = new someDisposableObject();
          try
          {
            // Do Something
          }
          finally
          {
             if (someDisposableObject != null)
             {
                 ((IDisposable) someDisposableObject).Dispose();
             }
          }
          

          看这篇文章:http://msdn.microsoft.com/en-us/library/yh598w02.aspx

          【讨论】:

            【解决方案7】:

            有一次我能想到你 wouldn't 想要在连接上使用“使用”的地方是在 ClassFactories 上用于连接对象(例如 DataReaders),例如考虑情况

            private IDataReader CreateReader(string queryString,
                string connectionString)
            {
                SqlConnection connection = new SqlConnection(connectionString);
                SqlCommand command = new SqlCommand(queryString, connection);
                connection.Open();
                return command.ExecuteReader(CommandBehavior.CloseConnection);
                // Don't close connection
            }
            

            (改编自 MSDN - MSDN 上的示例简直是愚蠢的)

            另一个原因是 WCF ServiceReference 'clients' - 如果通道出现故障,则“使用”会隐藏实际异常。但这只是一个错误的实现恕我直言。

            【讨论】:

              【解决方案8】:

              • 可以嵌套 4、5、10 个 using 语句来确保所有对象都被释放吗?

              回复:你不能限制使用嵌套的“使用块”。

              • 我在什么时候做错了,我应该考虑修改吗?

              回复:如果你有很多嵌套的“使用块”。请尝试如下。

                      using (var con = new SqlConnection(connStr))
                      using (var cmd = new SqlCommand(queryStry))
                      using (var rs = cmd.ExecuteReader())
                      {
                          while (rs.Read())
                          {
                              //Code.
                          }
                      }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-01-20
                • 1970-01-01
                • 2018-07-05
                • 2012-01-14
                • 2020-12-19
                • 1970-01-01
                相关资源
                最近更新 更多