当在using语句内引发异常时,Dispose是否仍会被调用?


103

在下面的示例中,如果在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();
}

有关:

引发异常时,确保关闭SQL连接的正确方法是什么?

Answers:


112

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

也可以看看:


5
只是指出连接类,如果您对它们进行反射,您会看到Dispose()确实在内部调用Close()。如果它处于状态就可以。
克里斯·马里西克

2
你是对的,的确如此。但是,我故意没有提及它,因为我不想误导任何人以为这与IDisposable或关联的模式有关。该特定实现调用Close()的事实是实现的细节,而不是模式。
杰夫·耶茨(

3
MSDN使用文档还可以确认以下答案:using语句可确保即使在调用对象的方法时发生异常,也将调用Dispose。通过将对象放在try块中,然后在finally块中调用Dispose,可以达到相同的结果。实际上,这就是编译器翻译using语句的方式。
宽带

20

这是反射器解码您的代码生成的IL的方式:

私有静态void Main(string [] args)
{
    SqlConnection conn =新的SqlConnection(“ ...”);
    尝试
    {
        conn.Open();
        做东西();
    }
    最后
    {
        如果(conn!= null)
        {
            conn.Dispose();
        }
    }
}

所以答案是肯定的,如果

做东西()
引发异常。


如果conn.Open()抛出异常,则添加。:D
Jeff Yates

当然可以。如果using子句引发块之后的内容,则连接将被关闭。如果“ new SqlConnection(...)”引发,则不会执行finally块的唯一方法,但是在那种情况下,您实际上没有有效的打开连接来关闭。这样很好
2009年

-1

在此代码中不会调用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块会处理异常。尝试在没有调试器的情况下运行它。
LarsTech

我运行了完全相同的代码,它确实调用了Dispose()。您确定答案正确吗?
Dnomyar96
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.