如何在ADO.NET对象上调用Dispose?

问题描述:

实现IDbConnectionIDbCommandIDataReader的数据库访问类都实现IDisposable,但很明显,命令和读者都依赖于连接上。我的问题是,我必须单独Dispose()每个这些对象还是将处置Connection对象处置其他对象?如何在ADO.NET对象上调用Dispose?

也就是说,我能做到这一点,并保证我不会冒着留下任何非托管资源不被释放:

using (IDbConnection conn = GetConnection()) 
{ 
     IDbCommand cmd = conn.CreateCommand(); 
     cmd.CommandText = " ..... "; 
     IDataReader rdr = cmd.ExecuteReader(); 
     while (rdr.Read()) 
     { 

     } 
} 

还是我必须这样做,而不是:

using (IDbConnection conn = GetConnection()) 
{ 
    using (IDbCommand cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = " ..... "; 
     using (IDataReader rdr = cmd.ExecuteReader()) 
     { 
      while (rdr.Read()) 
      { 

      } 
     } 
    } 
} 

或者这个实现是依赖的,所以它可能会使用一个数据库的提供者,但不适用于其他的?

最好的策略是使用所有ADO.NET对象中的使用块 - 句号。

稍微反映一下各种ADO.NET对象,表明如果不关闭/处置,事情或多或少会落在地板上。这样做的效果将取决于你正在使用哪些提供程序 - 如果你正在使用下面的非托管句柄(ODBC,OleDb等),你可能会泄漏内存,因为我什么也没有看到在终结者的方式。如果它是一个全能管理的提供者(例如SqlClient),它最终会得到清理,但取决于你所持有的对象,最终可能会在数据库服务器上使用比您想要的更长的资源。

您应该单独处理它们,或者也可以使用提供的解决方案here

单独处置它们。 Reader和Command对象完全有可能在其处理例程中执行更多的操作,而不仅仅是破坏连接(现在或将来的ADO.NET版本)。所以为了(a)要明确,并且(b)要安全,你应该单独处理它们。

它们实现IDisposable的事实表明,当你完成对象时,你应该总是运行Dispose例程,所以最好不要尝试和猜测接口,它不会给你带来任何好处,并且你可能最终会泄漏内存和句柄。

虽然在嵌套using语句时可以使代码看起来更清晰,但您仍可以执行某些操作。例如:

(using SqlConnection conn = new SqlConnection()) 
(using SqlCommand comm = new SqlCommand()) 
{ 
    //Do stuff 
} 

这看起来比嵌套牙套更整洁(在我看来)。

您应该单独处置它们。即使处置IDbConnection会将所有内容处理掉(我不知道它是否真的存在,我也不关心,因为后面的原因),您应该按将来时间进行编程。明天有人会编辑该代码并在同一连接上发出一个新命令,然后它会问他为什么会收到连接仍在使用中的错误(因为IDataReader没有处理)。

使用语句的主要优点是资源释放管理。通常,.NET Framework垃圾收集器控制资源分配和释放。通过使用声明,我们可以控制它。因此,using语句实现了一个包含公共Dispose()方法的IDisposible接口。

此外,您也可以始终手动调用Dispose()方法以释放内存中的资源或对象。

希望这有助于。