【问题标题】:Using statement and the IDisposable interfaceusing 语句和 IDisposable 接口
【发布时间】:2013-07-30 00:14:31
【问题描述】:

在 using 语句中声明的变量是否因为在 using 块的范围内而被一起处置?

我需要做什么:

using (SomeIdisposableImplementation foo = new SomeIdisposableImplementation())
{
    using(SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2())
    {

    }
}

或者这样就足够了,“bar”是否与“foo”一起设置?

using (SomeIdisposableImplementation foo = new SomeIdisposableImplementation())
{
    SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2();
}

【问题讨论】:

  • 你在SomeIdisposableImplementation2中错过了=吗?

标签: c# vb.net


【解决方案1】:

或者这样就足够了,“bar”是否与“foo”一起设置?

不,bar 不会被丢弃。

using 语句转换为try-finally 块,因此即使发生异常,finally 块也能确保调用Dispose 方法。

关注

using (SomeIdisposableImplementation foo = new SomeIdisposableImplementation())
{
    SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2();
}

翻译成

{
    SomeIdisposableImplementation foo;
    try
    {
        foo = new SomeIdisposableImplementation();
        SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2();
    }
    finally
    {
        if (foo != null)
            foo.Dispose();
    }
}

离开 bar 未处置。

【讨论】:

    【解决方案2】:

    要让它们都使用 using 语句处理,您不必嵌套它们,但是您可以这样写

    using (SomeIdisposableImplementation foo = new SomeIdisposableImplementation())
    {
        using(SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2())
        {
    
        }
    }
    

    作为

    using (SomeIdisposableImplementation foo = new SomeIdisposableImplementation())
    using(SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2())
    {
    
    
    }
    

    【讨论】:

      【解决方案3】:

      在第二个版本中 bar 将超出范围但不会被释放。但是您可以使用命令将 foo 和 bar 放在同一个中:

      using (SomeIdisposableImplementation foo = new SomeIdisposableImplementation(), SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2())
      {
          // use foo and bar
      }
      

      你也可以把变量放到 using 命令中:

      SomeIdisposableImplementation foo = new SomeIdisposableImplementation();
      SomeIdisposableImplementation2 bar = new SomeIdisposableImplementation2();
      using (foo, bar)
      {
          // use foo and bar
      }
      

      【讨论】:

      • 这个答案的第一句话是正确的。其余的都是错误的。
      • 您编辑的第二个选项 Roland 不正确。如果bar = new SomeIdisposableImplementation2() 抛出异常,或者在进入using 块之前发生线程异常foo(和bar)将永远不会被释放。
      • 正确的语法是using(S1 foo = new S1()) using (S2 bar = new S2()) { ... },或者如果foobar 是同一类型,则为using(S1 foo = new S1(), bar = new S1()) { ... }。如果using(S1 foo = new S1(); S2 bar = new S2()) { ... } 合法就好了,但事实并非如此。
      • @ChrisSinclair: using 在面对线程中止异常时根本不健壮。考虑:S1 foo = null; try { foo = new S1(); ... } finally { if (foo != null) foo.Dispose(); }。现在假设S1的构造函数期间抛出了线程中止异常,但是之后构造函数创建了非托管资源。 foo 永远不会被分配,因此它在finally 中仍然为空。可以在这里释放资源的唯一方法是在终结器中。这就是为什么您需要始终编写终结器以在面对部分构造的对象时保持稳健。
      • @ChrisSinclair:是的,我的观点是,尽管注意到这里显示的代码在面对线程中止异常时并不健壮是正确的,但这本身并不是使用的动机using 语句,因为 using 语句对于线程中止也不可靠。一般来说,我真的很少关心在异常情况下清理资源,因为它是异常的。您根本无法在所有异常情况下清理资源,并且根据定义它们是异常的;而是担心在典型情况下总是清理。
      猜你喜欢
      • 2018-04-04
      • 1970-01-01
      • 2011-04-02
      • 2016-10-24
      • 2012-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      相关资源
      最近更新 更多