【问题标题】:Does a using block guarantee that the object will not be disposed until the end of the block?using 块是否保证对象在块结束之前不会被释放?
【发布时间】:2013-07-08 04:30:21
【问题描述】:

我知道using 块确保被“使用”的IDisposable 对象将在块的末尾被释放 - 但它保证该对象之前不会被释放那么呢?

换句话说,如果我有:

using (new DisposableObject()) {
  // blah blah
}

我能否确定DisposableObject 直到块结束时才会被释放,或者垃圾收集器是否会检测到我在块内没有处理它,并立即释放它?

【问题讨论】:

    标签: c# idisposable using


    【解决方案1】:

    不,它没有。没有什么能阻止你做:

    using(var myObject = new DisposableObject())
    {
        myObject.Dispose();
    }
    

    在这种情况下究竟会发生什么取决于DisposableObject 的语义。它可能会抛出异常,或者它可能对Dispose 被调用两次感到非常满意。

    需要注意的是,对象处理和垃圾回收是完全不同的概念。仅仅因为一个对象被释放并不意味着它会被垃圾回收,仅仅因为一个对象被垃圾回收并不意味着它会被释放。

    一旦对该对象的所有引用都被销毁或无法访问,则该对象可能会被垃圾回收。当代码在using-block 中运行时,这不会发生,因为该块本身具有对该对象的引用。

    【讨论】:

    • 我认为您错过了问题的重点。问题是 GC 是否会在 using 块结束之前调用终结器。
    • +1 感谢您在垃圾收集和对象处理之间做出区分,这在我之前并不清楚。所以改写我的问题:在我的问题的代码中,我可以依赖 DisposableObject 在 using 块结束之前没有被 disposed 吗?
    • @Shaul 不,没有办法保证变量 myObject 在 using 块结束之前不会被释放。该对象可能会在对其的所有引用都无法访问后被释放,但是当您在 using 块中时,不会发生这种情况,因为您已经在那里获得了对它的引用。
    • 但您可以保证 CLR 不会 处理它 - 只有用户代码可能会处理它。
    【解决方案2】:

    您的对象只会被释放一次,并且不会在 using 块结束之前被 GC。

    规范保证当您拥有using (expression) statement 并且表达式的类型是可空类型(称为ResourceType)时,它会扩展为:

    {
       ResourceType resource = expression;
       try {
          statement;
       }
       finally {
          if (resource != null) ((IDisposable)resource).Dispose();
       }
    }
    

    Dispose 将在块的末尾被调用一次,并且有一个本地生成的,它保留对您的一次性对象的引用。本地阻止对象在 using 块结束之前被 GC。

    【讨论】:

    • +1 这是给出的最清晰的解释,值得回答。谢谢!
    【解决方案3】:

    我认为您更想了解垃圾收集而不是处理。

    垃圾收集器不会收集using 块内的对象。即使您专门调用了Dispose 方法,仍然存在对它的活动引用,因此不会被收集。

    为using 块生成的代码以检查对象是否可以被释放结束,因此使用将在using 块期间保持对象处于活动状态。

    【讨论】:

      猜你喜欢
      • 2016-07-11
      • 2012-01-04
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 2021-05-13
      • 2011-03-16
      • 2017-10-03
      相关资源
      最近更新 更多