【问题标题】:Does Dispose still get called when exception is thrown inside of a using statement?在 using 语句中引发异常时,是否仍会调用 Dispose?
【发布时间】:2010-10-05 19:46:43
【问题描述】:

在下面的示例中,如果在using 语句中引发异常,连接是否会关闭并释放?

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    // stuff happens here and exception is thrown...
}

我知道下面的这段代码会确保它确实如此,但我很好奇 using 语句是如何做到的。

var conn;
try
{
    conn = new SqlConnection("...");
    conn.Open();
    // stuff happens here and exception is thrown...
}
// catch it or let it bubble up
finally
{
    conn.Dispose();
}

相关:

What is the proper way to ensure a SQL connection is closed when an exception is thrown?

【问题讨论】:

    标签: c# asp.net using-statement


    【解决方案1】:

    是的,using 将您的代码包装在一个 try/finally 块中,其中 finally 部分将调用 Dispose()(如果存在)。但是,它不会直接调用Close(),因为它只检查正在实现的IDisposable 接口以及Dispose() 方法。

    另见:

    【讨论】:

    • 只是指出连接类,如果你对它们进行反射,你会看到 Dispose() 确实在内部调用了 Close()。如果它处于某种状态,它可以。
    • 你是对的,确实如此。但是,我故意没有提及它,因为我不想误导任何人认为这与 IDisposable 或相关模式有关。这个特定实现调用 Close() 的事实是实现的细节,而不是模式。
    • MSDN using documentation 也证实了这个答案:using 语句确保即使在调用对象上的方法时发生异常,也会调用 Dispose。您可以通过将对象放在 try 块中,然后在 finally 块中调用 Dispose 来获得相同的结果;事实上,编译器就是这样翻译 using 语句的。
    【解决方案2】:

    这就是反射器对代码生成的 IL 进行解码的方式:

    私人静态无效主要(字符串[] args) { SqlConnection conn = new SqlConnection("..."); 尝试 { conn.Open(); 做东西(); } 最后 { 如果(连接!= null) { conn.Dispose(); } } }

    所以答案是肯定的,如果

    DoStuff()
    抛出异常。

    【讨论】:

    • 如果 conn.Open() 抛出异常则添加。 :D
    • 是的。如果 using 子句之后块中的任何内容引发异常,则连接将被关闭。不执行 finally 块的唯一方法是抛出“new SqlConnection(...)”,但在这种情况下,您实际上不会有一个有效的打开连接来关闭。所以没关系。
    【解决方案3】:

    Dispose() 在这段代码中没有被调用。

    class Program {
        static void Main(string[] args) {
            using (SomeClass sc = new SomeClass())
            {
                string str = sc.DoSomething();
                sc.BlowUp();
            }
        }
    }
    
    public class SomeClass : IDisposable {
        private System.IO.StreamWriter wtr = null;
    
        public SomeClass() {
            string path = System.IO.Path.GetTempFileName();
            this.wtr = new System.IO.StreamWriter(path);
            this.wtr.WriteLine("SomeClass()");
        }
    
        public void BlowUp() {
            this.wtr.WriteLine("BlowUp()");
            throw new Exception("An exception was thrown.");
        }
    
        public string DoSomething() {
            this.wtr.WriteLine("DoSomething()");
            return "Did something.";
        }
    
        public void Dispose() {
            this.wtr.WriteLine("Dispose()");
            this.wtr.Dispose();
        }
    }
    

    【讨论】:

    • 这能回答 OP 的问题吗??
    • 是的。答案是不。 Dispose() 不会在附加的代码中被调用。此外,抛出的异常没有得到处理,程序就会崩溃。
    • 您一定是查看了错误的文件。 “Dispose()”被写入您的临时文件。没有人声称 using-block 会处理异常。尝试在没有调试器的情况下运行它。
    • 我运行了完全相同的代码,它确实调用了 Dispose()。你确定你的答案是正确的?
    猜你喜欢
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多