使用带有connection.open的语句

我正在查看一些代码并与同事讨论。

特别是一段看起来像这样的代码。

[Test] public void TestNormalWay() { using(var cn = GetConnection()) { cn.Open(); // do stuff } } 

问题出现了:

“为什么不将cn.Open移动到GetConnection方法中。”

我说如果“打开”抛出一个exception处理就不会被调用。 他的回答是

“那么什么。连接没有打开,为什么需要关闭(或处置)?”

对我来说,这只是一个不想知道我是否需要处理/关闭的问题所以我会重复cn.Open代码而不是将其移动到共享函数中。

它很有趣……所以我在SQL Server连接池(ADO.NET)上做了一些阅读

对我而言,目前尚不清楚是否存在调用cn.Open并抛出exception需要调用dispose的场景。

所以在下面的例子中,“TestNormalWay”和“WhyNotDoItThisWay”之间是否存在任何差异

  protected static DbConnection GetConnection() { DbConnection cn = new SqlConnection("SomeConnecitonstring... "); return cn; } protected static DbConnection GetConnectionDangerousVersion() { DbConnection cn = new SqlConnection("SomeConnecitonstring... "); cn.Open(); // this will throw.. .dispose not called return cn; } [Test] public void TestNormalWay() { using(var cn = GetConnection()) { cn.Open(); // do stuff } } [Test] public void WhyNotDoItThisWay() { using(var cn = GetConnectionDangerousVersion()) { // do stuff } } 

您编写代码的方式总是希望在创建连接后立即打开连接,因此没有任何区别。

但是,您可以多次打开和关闭连接,并且在代码设计中这样做有很大的不同。

我可能想编写一些代码,其中我有一个长时间运行的例程,它接受一个连接对象,随着时间的推移打开并关闭它。 例程可能不关心连接对象是如何创建的。 因此,将创建连接的行为与打开和关闭它的行为分开是有利的。

关于资源管理问题,我同意这不是问题。 创建SQL连接对象本身并不会锁定任何资源,而是打开它获取池化连接的行为。 如果open返回exception,我认为假设连接未打开是合理的。

我倾向于只返回SqlConnection的实例而不在方法中调用Open() 。 如果需要,应该这样做。 您的实用程序function不需要它。

其中一个原因是,有些对象需要SqlConnection ,但不一定需要打开它们。 例如, SqlDataAdapter接受SqlConnection ,并在其自身内处理它的打开和关闭。 当然,你可以在传递之前打开一个连接,但是你必须明确地关闭它。

稍微退一步,调用代码应该负责处理与SqlConnection完全相关的操作。

您可以在第二个“危险”版本中围绕.Open()调用放置一个try / catch,这样如果它在打开时抛出exception仍然处理连接。

在SqlConnection的内部达到顶峰之后,我几乎确信这无关紧要。 快速测试似乎证实了这一点:

 static void Main( string[] args ) { Func getConnection = () => { var connection = new SqlConnection( "Initial Catalog=myDatabase;Server=(local);Username=bogus;password=blah;Connect Timeout=10;" ); connection.Open(); return connection; }; while(true) { try { using( var connection = getConnection() ) { var cmd = new SqlCommand( "SELECT 1", connection ) {CommandType = CommandType.Text}; cmd.ExecuteNonQuery(); } } catch ( Exception ) { // ignore exception } } } 

我把这个代码运行了几分钟,并附带了一个分析器。 它不仅运行速度很快,而且还没有泄漏任何内存。 这几乎让我相信可以在GetConnection方法中打开连接。

当然,此处发布的所有其他论点仍然有效; 如果你要立即使用它,你应该只打开连接。