【问题标题】:Are all disposable objects instantiated within a using block disposed?是否所有一次性对象都在 using 块中实例化?
【发布时间】:2010-02-17 22:34:57
【问题描述】:

这是我过去多次问过自己的一个问题,因为我嵌套了 5 深的语句。

阅读docs 并没有发现任何关于在块中实例化的其他一次性用品的任何提及,我认为这是 SO 档案的一个很好的 Q。

考虑一下:

using (var conn = new SqlConnection())
{
    var conn2 = new SqlConnection();
}

// is conn2 disposed?

【问题讨论】:

    标签: c# vb.net dispose using-statement


    【解决方案1】:

    不,他们不是。只有在 using 子句中明确列出的变量集才会被自动释放。

    【讨论】:

    • 所以你需要嵌套你使用的 6 深 :-)
    【解决方案2】:

    显然我有答案... ;-)

    答案是否定的。只释放 using 声明中的对象

    [Test]
    public void TestUsing()
    {
        bool innerDisposed = false;
        using (var conn = new SqlConnection())
        {
            var conn2 = new SqlConnection();
            conn2.Disposed += (sender, e) => { innerDisposed = true; };
        }
    
        Assert.False(innerDisposed); // not disposed
    }
    
    [Test]
    public void TestUsing2()
    {
        bool innerDisposed = false;
        using (SqlConnection conn = new SqlConnection(), conn2 = new SqlConnection())
        {
            conn2.Disposed += (sender, e) => { innerDisposed = true; };
        }
        Assert.True(innerDisposed); // disposed, of course
    }
    

    【讨论】:

    • 仅供参考:在我提交问题之前,我已经在剪贴板中找到了答案。
    • 我认为从技术上讲,该线程可能会以某种方式暂停,这样SqlConnection.Dispose() 将在conn2 变量超出范围和您的Assert 行之间被Component.Finalizer() 调用。这里有一个竞争条件,不是吗?
    【解决方案3】:

    如果您想了解 using 语句的确切规则,请参阅规范的第 8.13 节。你所有的问题都应该在那里得到清楚的回答。

    【讨论】:

    • @eric,感谢您的参考。在对我的答案中的测试进行了怀疑后,我发布了这个 Q,更多的是作为公共服务而不是其他任何东西。
    • @Eric:是否愿意为那些不知道如何访问 MSDN 的人提供规范的链接?
    【解决方案4】:

    不,它不起作用,conn2 不会被处置。 请注意,倍数 using 是我允许不使用方括号以提高可读性的唯一情况:

            using (var pen = new Pen(color, 1))
            using (var brush = new SolidBrush(color))
            using (var fontM60 = new Font("Arial", 15F, FontStyle.Bold, GraphicsUnit.Pixel))
            using (var fontM30 = new Font("Arial", 12F, FontStyle.Bold, GraphicsUnit.Pixel))
            using (var fontM15 = new Font("Arial", 12F, FontStyle.Regular, GraphicsUnit.Pixel))
            using (var fontM05 = new Font("Arial", 10F, FontStyle.Regular, GraphicsUnit.Pixel))
            using (var fontM01 = new Font("Arial", 8F, FontStyle.Regular, GraphicsUnit.Pixel))
            using (var stringFormat = new StringFormat())
            {
            }
    

    这样,嵌套的using 没什么大不了的。

    【讨论】:

      【解决方案5】:

      没有。 Using 导致 using 语句中的对象被释放。如果您希望处理两个对象,则应将其重写为:

      using (var conn = new SqlConnection())
      {
          using (var conn2 = new SqlConnection())
          {
              // use both connections here...
          }
      }
      

      或者,您也可以使用更简洁的语法:

      using (SqlConnection conn = new SqlConnection(), conn2 = new SqlConnection())
      {
          // use both connections here...
      }
      

      【讨论】:

      • 注意,你可以写得更紧凑。 "使用(SqlConn conn1 = new SqlConn(), conn2 = new SqlConn()) { 东西}"
      • 此外,using 语句而不是块 (using(var conn=new SqlConnection())using(var conn2=new SqlConnection()){ ... }) 将在 Visual Studio 中很好地排列。它不会缩进第二个using
      • @Eric Lippert:我也更新以显示该选项... @Jeffrey:我倾向于不这样做,因为 StyleCop 抱怨说,如果您不为每个语句使用大括号。
      【解决方案6】:

      没有。使用 ILDASM 或 Reflector 检查生成的 IL。

      【讨论】:

        【解决方案7】:

        只会释放using() 中的变量,而不是实际的代码块。 .

        【讨论】:

          猜你喜欢
          • 2017-09-23
          • 1970-01-01
          • 2013-09-15
          • 1970-01-01
          • 1970-01-01
          • 2021-08-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多