使用using块是否保证对象在块结束前不会被释放?

5
我知道使用 using 块可以确保在块末尾处释放“使用”中的 IDisposable 对象 - 但它是否保证在此之前不会释放该对象呢?
换言之,如果我有以下代码:
using (new DisposableObject()) {
  // blah blah
}

我能确定DisposableObject在代码块结束前不会被释放吗?或者垃圾回收器会检测到我在代码块内没有引用它,然后立即释放它吗?

3个回答

6

不,它并没有。你可以随意执行以下操作:

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

在这种情况下会发生什么事情,实际上取决于 DisposableObject 的语义。它可能会抛出异常,也可能对 Dispose 被调用两次毫不在意。
需要注意的是,对象处理和垃圾回收是完全不同的概念。一个对象被处理并不意味着它将被垃圾回收,而一个对象被垃圾回收也并不意味着它将被处理。
只有当所有对该对象的引用都被销毁或不可访问时,该对象才会被垃圾回收。但在 using 块内运行代码时,这是不可能的,因为该块本身具有对该对象的引用。

我认为你没有理解问题的要点。问题在于GC是否会在using块结束之前调用终结器。 - CodesInChaos
谢谢您明确垃圾回收和对象处理之间的区别,这在我之前并不清楚。那么重新表述我的问题:在我的代码中,我能否依赖于 DisposableObjectusing 块结束之前不被 处理 - Shaul Behr
@Shaul,没有办法保证变量myObject在使用块结束之前不被释放。该对象可能会在所有对其的引用都无法访问时被释放,但是当您在使用块中时,这不会发生,因为您现在对它有一个引用。 - p.s.w.g
但是您可以保证CLR 不会 处置它 - 只有用户代码可能会处理它。 - Matthew Watson

4

您的对象只会在using块结束时被释放,而且不会在此之前被垃圾回收。

规范保证当您使用using(expression) statement并且expression的类型是可空类型(称其为ResourceType)时,它会被展开为:

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

Dispose会在块结束时被调用,并生成一个本地引用来保留您的可处置对象。该本地变量可以防止在using块结束之前,对象被垃圾收集器回收。


+1 这是最清晰的解释,并值得获得答案分数。谢谢! - Shaul Behr

2
我认为您更想了解垃圾回收而不是处理垃圾。
垃圾收集器不会收集使用块中的对象。即使您明确调用Dispose方法,仍然存在对它的活动引用,因此它不会被收集。
为using块生成的代码以检查对象是否可以处理结束,因此在using块期间使用将保持对象处于活动状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接