using语句只能释放它创建的第一个变量吗?

7

假设我有一个可丢弃的对象MyDisposable,它的构造函数参数是另一个可丢弃的对象。

using(MyDisposable myDisposable= new MyDisposable(new AnotherDisposable()))
{
     //whatever
}

假设 myDisposable 没有在它的 dispose 方法中释放 AnotherDisposable,那么这个方法只会正确释放 myDisposable 吗?还是也会释放 AnotherDisposable

2
是的,它确实没有处理AnotherDisposable,你需要手动管理。 - cuongle
由于AnotherDisposableMyDisposable实现中被使用,因此应该在MyDisposable实现中进行处理。 - AgentFire
6个回答

10

using 是一个的等价写法

MyDisposable myDisposable = new MyDisposable(new AnotherDisposable());
try
{
    //whatever
}
finally
{
    if (myDisposable != null)
        myDisposable.Dispose();
}
因此,如果myDisposable没有在AnotherDisposable上调用Dispose,using也不会调用它。

5
为什么不将它们嵌套起来?
using(var outer = new AnotherDisposable())
{
   using(var inner = new MyDisposable(outer))
   {
      //whatever
   }

}

现在,至少您可以确信它们会得到正确的处理。

问题在于使用双重using会导致FxCop显示CA2202:对象不应被多次处理的警告,但实际情况是我知道内部可处理对象(innerDisposable)由外部可处理对象(outerDisposable)处理,所以我想知道是否可以这样做。 - Fabio Marcolini
+1,处理清理的最佳方式。请注意,第二组括号甚至不是必需的。这取决于您的格式设置偏好,但您可以将使用语句直接堆叠在彼此上方,并使用相同的括号来表示作用域。 - Amicable

1
C# 的 using 语句提供了一种在调用实现 IDisposable 接口对象的 Dispose 方法时,使用 try/finally 块的语法快捷方式。例如:
using (FileStream fs = new FileStream ("myFile.txt", FileMode.Open))
{
// ... Write to the file ...
}

编译器将其转换为: FileStream fs = new FileStream("myFile.txt", FileMode.Open);
try
{
// ... Write to the file ...
}
finally
{
if (fs != null) ((IDisposable)fs).Dispose();
}

finally 块确保在抛出异常或代码提前退出块时,调用 Dispose 方法。

因此,仅使用单个块将确保单个可处理对象被处理。另一方面,您可以使用嵌套的 using 语句,例如

using (myDisposable d = new myDisposable())
{
  using(Disposable2 d2 = new Disposable2())
  {
// do something and dispose...
  }
}

这将被转换为

try
{
  // work around for myDisposable  

    try
     {
      // work around for Disposable2 
     }
    finally
    {
    if (d2 != null) 
         ((IDisposable)d2 ).Dispose();
    }    
}
finally
{
     if (d!= null)
          ((IDisposable)d).Dispose();
}

1
它并不会“处理”任何东西。它调用其中使用的对象的Dispose方法。你需要清理其他内容,可能需要在其他对象上调用dispose。

0
在这种情况下,它不会处理 AnotherDisposable。 有两个解决方案。
首先,您通常要执行以下操作:
using (AnotherDisposable anotherDisposable = new AnotherDisposable())
using (MyDisposable myDisposable= new MyDisposable(anotherDisposable))
{
}

然而,还有一种不同的方法。当一个类使用可处理对象时,它本身会负责处理所取得的对象。例如,包装StreamStreamReader将处理它所包装的Stream的处理。这意味着您选择的结构将起作用。您可以在MyDisposable中实现相同的功能,然后您采取的方法就可以了。


如果MyDisposable的构造函数不仅承诺MyDisposable.Dispose将处理传递到构造函数中的对象,而且在构造函数本身中发生任何异常时,传递的项目将立即被处理,则using (MyDisposable myDisposable = new MyDisposable(new AnotherDisposable()) {...}模式才是安全的。这种模式比应该正确处理要困难得多。 - supercat

0

using语句中,您只初始化了一个可处理的变量。 AnotherDisposable嵌套对象是通过正常初始化创建的,而不是通过using创建的。 因此,只有使用using语句创建的myDisposable变量将自动被处理。


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