【问题标题】:Do I need to close and dispose the SQLConnection explicitly?我是否需要明确关闭并处置 SQLConnection?
【发布时间】:2025-12-22 09:50:18
【问题描述】:
SqlDataReader rdr = null;
con = new SqlConnection(objUtilityDAL.ConnectionString);
using (SqlCommand cmd = con.CreateCommand())
{
    try
    {
        if (con.State != ConnectionState.Open)
            con.Open();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(Parameter);
        cmd.CommandText = _query;
        rdr = cmd.ExecuteReader();
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

在上面的代码中,sqlconnection 在托管代码中打开。那么,连接对象是否会在 USING 范围结束时自动释放?

【问题讨论】:

  • 您的连接对象不在 using 语句的范围内。

标签: c# asp.net ado.net sqlconnection


【解决方案1】:

您必须关心SqlConnection 的处置,因为它是一次性物品。你可以试试这个:

using(var sqlConnection = new SqlConnection(objUtilityDAL.ConnectionString))
{
    using (SqlCommand cmd = con.CreateCommand())
    {
        // the rest of your code - just replace con with sqlConnection
    }
}

我建议您将 con 替换为局部变量 - 如果还没有的话(从您发布的代码中看不出来)。不需要为此目的使用类字段。只需创建一个局部变量,跟踪它会更加清晰。

【讨论】:

  • 看起来con 可能是一个字段。我不建议在using 语句中使用字段。因为一旦它在此方法中被处置,并且您尝试在其他地方使用该字段,您将得到一个例外,因为该对象已被处置。不会更好地使用局部变量来避免上述情况吗?此外,与局部变量相比,被处理的字段甚至没有任何优势。还是我错了?
  • @L.Guthardt 通过快速阅读这篇文章,我没有注意到这可能是一个类字段:)。说得好 !正如我在更新中所写,我认为为此目的使用类字段不是一个好主意。
  • 谢谢。 :) 很高兴您更新了答案以添加此信息。 +1
  • 非常感谢克里斯托斯。您建议我使用局部变量而不是类变量的观点是有道理的,因为它将被放置在方法中。我会改变逻辑。再次感谢!!
【解决方案2】:

您应该Dispose 每个临时 IDisposable 实例手动创建,即将它们包装到using

   // Connecton is IDisposable; we create it 
   //   1. manually - new ...
   //   2. for temporary usage (just for the query)
   using (SqlConnection con = new SqlConnection(objUtilityDAL.ConnectionString)) {
     // Check is redundant here: new instance will be closed 
     con.Open();

     // Command is IDisposable
     using (SqlCommand cmd = con.CreateCommand()) {
       cmd.CommandType = CommandType.StoredProcedure;
       cmd.Parameters.Add(Parameter);
       cmd.CommandText = _query;

       // Finally, Reader - yes - is IDisposable 
       using (SqlDataReader rdr = cmd.ExecuteReader()) {
         // while (rdr.Read()) {...}
       }
     }   
   }

请注意

   try {
     ...
   }
   catch (Exception ex) {
     throw ex;
  } 

至少是冗余(它什么都不做,只是重新抛出异常,同时丢失堆栈跟踪),这就是为什么可以退出

【讨论】:

  • 非常感谢德米特里·比琴科
  • 不要重新抛出异常,否则您将丢失堆栈跟踪信息...仅使用throw;
【解决方案3】:

一般:

在 .Net 框架中,不会自动处理任何内容。否则我们不需要IDisposable 接口。垃圾收集器只能处理托管资源,因此每个非托管资源都必须在 dispose 方法的代码中处理。

因此,作为一项规则,实现IDisposable 的每个类的每个实例都必须通过调用Dispose 方法显式处理或使用using 语句隐式处理。

作为最佳实践,您应该努力使用任何实现 IDisposable 接口的东西作为 using 语句中的局部变量:

using(var whatever = new SomeIDisposableImplementation())
{
    // use the whatever variable here
}

using 语句是语法糖。编译器将其翻译成这样的:

var whatever = new SomeIDisposableImplementation();
try
{
    // use the whatever variable here
}
finally
{
    ((IDisposable)whatever).Dispose();
}

由于finally 块保证运行,无论try 块中发生什么,您的IDisposable 实例都保证被正确处置。

具体用SqlConnectionin order to return the connection object back to the connection pool,完成后必须dispose(Dispose方法也会关闭连接,所以不需要显式关闭)——所以SqlConnection的正确用法是总是作为using 语句中的局部变量:

using(var con = new SqlConnection(connectionString))
{
    // do stuff with con here
}

【讨论】:

  • 非常感谢@Zohar Peled
  • 很高兴为您提供帮助 :-)