使用“Using”时,在Finally中关闭SqlConnection

8

我希望在Finally语句块中关闭SqlConnection连接,因为using语句不能真正地关闭该连接且连接池会被填满。但是,由于在Finally语句块中无法访问conn对象,所以我不知道正确的关闭方法。

try 
{
    using (var conn = new SqlConnection(_dbconnstr)) 
    {
        //...
    }
}
catch (Exception ex)
{
    //...
}
finally 
{
    conn.Close //?!?!?!?!???
}

3
您遇到了其他问题。using在内部实现上是一个try/finally块,其中Dispose在finally块中调用。对于SqlConnection来说,CloseDispose是可以互换的。 - Damien_The_Unbeliever
正如回答中所提到的,我建议您检查DataReaders的相同事项:您关闭连接的方式是正确的。 - Larry
哦,我完全忽略了完整的Using块在try{}块内部的点。我读错了这个,因为括号的缩进方式很奇怪。 - Larry
6个回答

15
using (var conn = new SqlConnection(_dbconnstr)) 
{
    //code
}

被扩展为:

SqlConnection conn = new SqlConnection(_dbconnstr);
try
{
    //code
}
finally
{
    conn.Dispose();
}

你应该处理错误,但可以忘记关闭连接。


1
一个小问题:您的扩展不正确。如果构造函数抛出异常,则在finally块中尝试调用Dispose将引发NullReferenceException并隐藏真正的错误。编译器实际上是将赋值放在try块之外,然后在finally块中进行了空检查后才调用Dispose - LukeH
@LukeH 因为赋值在 try lock 之前,所以不会抛出 NullReferenceException。因此,如果构造函数失败,执行不会进入 try..finally 块。 - RM.

8
你不需要在 finally 块中关闭 connusing 块将为您处理关闭连接。(实际上,除非您有其他需要在 finally 中处理的资源,否则在这种情况下,您可能根本不需要 try...finally。) using 块将转换为类似于以下内容的东西:
var conn = new SqlConnection(/*...*/);
try
{
    // ...
}
finally
{
    if (conn != null)
        ((IDisposable)conn).Dispose();
}
SqlConnection对象的Dispose方法将在finally块中被调用,Dispose方法会为您调用Close方法。

1
始终在 try 块内进行初始化。 - Claus Jørgensen
5
@Claus:我只是解释编译器生成的内容,它会在 try 块之前立即执行赋值操作,就像我展示的那样。在你点踩之前应该核实事实! - LukeH

2
据我所知,以下使用语句:
using (var conn = new SqlConnection(_dbconnstr)) 
{

}

等同于:
SqlConnection conn;
try
{
    //`using` scope operations are executed here
    conn = new SqlConnection(_dbconnstr));

}
catch
{
    //exceptions are bubbled
    throw;
}
finally
{
    //Dispose is always called
    conn.Dispose();
}

错误。这相当于执行以下操作:var conn = new SqlConnection(_dbconnstr); { ... } conn.Dispose(); 它与try/catch无关。{}在C#中表示作用域。 - Claus Jørgensen
1
@Claus Jørgensen: 那就意味着按照你的推理,这个问题的所有答案都是错误的吗?不对。至少涉及到 try/finally - Grant Thomas
1
不,只有大约一半。 (还请注意评论已更新) - Claus Jørgensen
1
@Claus Jørgensen:你的第一条评论没有意义——仅仅新建一个实例并期望能够到达Dispose调用_不是_ using 的工作方式:using 保证将调用Dispose,并且这发生在finally块中。 - Grant Thomas

2
退出使用块会调用对象上的.Dispose()方法,对于SqlConnection将关闭连接和任何打开的资源。
因此,tryfinally块是不必要的。

这不正确。如果系统想要处理错误,就需要使用try块。例如,在调试模式下记录异常消息非常有用。 - ModChowdhury

1
根据我的理解,连接对象的Dispose()方法将关闭连接。您不需要显式调用Connection.Close。

1
Dispose调用了.Close()方法。区别在于当对象被Dispose后,就无法重新打开它。 - Claus Jørgensen
1
是的,我没有考虑到那一点。但是如果我们使用了 "using" 关键字,那么调用 Connection.Close() 就没有意义了,对吧? - Anuraj

1

你使用 Using 关闭连接的方式是正确的。也许你忘记关闭一些 DataReader 了?


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