【问题标题】:Does `using` dispose all the the objects declared in it?`using` 会处理其中声明的所有对象吗?
【发布时间】:2012-09-13 16:31:29
【问题描述】:

我想知道如果我执行return 或throw 操作,在usingstatement 中创建的对象是否会被释放。示例如下。

using(SomeClass thing = new SomeClass())
{
  ...
  if(condition)
    return;
  ...
}

上面会混淆还是GC在这里值得信任?

【问题讨论】:

  • 当然,这就是首先引入using 块的全部意义所在。

标签: c#


【解决方案1】:

是的,会的。 using 语句将导致创建 finally 块。即使在相关的try 块中抛出异常,或者如果该try 块中有return 语句,finally 块的代码也会运行。

只有少数例外情况会导致finally 块的代码无法执行,它们都列在here 中,但我猜在您的情况下,您将能够承受这些后果.

【讨论】:

    【解决方案2】:

    using 相当于 try-finally 所以,是的,确实如此。

    【讨论】:

      【解决方案3】:

      dispose 如果它被实现,总是会被调用。它相当于在 finally 块中调用 dispose。

      【讨论】:

        【解决方案4】:

        它会处理,是的。它将在 CIL 代码中创建一个 finally 块。

        【讨论】:

          【解决方案5】:

          是的,因为 using 被编译器最终扩展为 try 。处置将发生在 finally 块内。此外,finally 将包含一个测试,以检查 using 中的变量是否为 null(以防构造函数出现异常)。

          【讨论】:

            【解决方案6】:

            在编写 using 语句时:

            using(SomeClass thing = new SomeClass())
            {
                //...
                if (condition)
                    return;
                //...
            }
            

            这将产生以下代码:

            SomeClass thing;
            try
            {
                thing = new SomeClass();
                //...
                if (condition)
                    return;
                //...
            }
            finally
            {
                if(thing != null)
                {
                    thing.Dispose();
                }
            }        
            

            所以所有声明为using ( /* HERE */ ) 的对象都会被自动释放。在 {} 中声明的对象不会。 但是您当然可以使用语句嵌套(或堆叠):

            using (var thing = new SomeClass())
                using (var another = new Another())
                    using (var somethingElse = new Whatever())
                    {
                        //...
                    }
            

            这当然只是写作的语法糖

            using (var thing = new SomeClass())
            {
                using (var another = new Another())
                {
                    using (var somethingElse = new Whatever())
                    {
                        //...
                    }
                }
            }
            

            因为当一个语句后面只有一个代码块(在这种情况下是另一个 using-block)时,您可以跳过花括号...

            当使用两个或多个相同类型的对象时,您可以在using-statement 中链接声明:

            using (MemoryStream stream = new MemoryStream(), stream2 = new MemoryStream())
            {
                //...
            }
            

            (感谢@Gratzy 指出)

            【讨论】:

              【解决方案7】:

              对我来说,问题与细节不匹配,细节已经在这里解决了一堆但不是标题问题......

              using 是否会释放其中声明的所有对象?

              不,它没有。它只为声明中的对象调用Dispose()。它不会为 在其中声明的对象调用Dispose()。

              我经常在代码中看到这种东西

              using(var sqlConn = new SqlConnection("connStr"))
              using(var sqlCmd = new SqlCmd("CmdText", sqlConn))
              {
                 sqlConn.Open();
                 var reader = sqlCmd.ExecuteReader();
                 while (reader.Read())
                 {
                   //stuff is done
                 }
              }
              

              这将在 sqlConn 和 sqlCmd 的作用域完成时处理并关闭它们,但是 在使用作用域中声明的 reader 没有自动调用 Dispose()为它。

              【讨论】:

              • 这是一个很好的答案。谢谢。但是,我想知道您是否可以详细说明消息标题和详细信息之间的不匹配。我重读了它,对我来说,它们之间的关联似乎很明显。但这是 my 的问题,所以 my 的想法(填补一些空白的忍者风格)可能比 your 更清楚。如果我只知道什么和怎么做,我会很乐意改变配方。
              • @KonradViltersten - 我的示例中的阅读器是在 using 块内声明和实例化的 - 正如您的标题所说的“在其中声明 ”。您问题的其余部分描述了作为 using 语句声明的 part 的变量。这也可以被认为是“在里面”,但我不认为是因为它不在“里面”。 HTH
              • 对不起,我不得不接受你的回答。显然,@servy 觉得编辑不符合我的初衷。很抱歉引起了骚动。
              • @KonradViltersten - 无需为不接受答案向我道歉。任何一种解释都可能是有效的,我只是想确保两者都在这里得到体现。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-11-18
              • 2012-09-18
              • 1970-01-01
              • 2011-02-10
              • 1970-01-01
              • 1970-01-01
              • 2013-02-22
              相关资源
              最近更新 更多