非托管资源,IDisposable和自定义类型

时间:2012-04-24 12:21:13

标签: c# garbage-collection idisposable unmanagedresources idbconnection

关于这个主题的另一个话题,因为我厌倦了阅读无数主题以找到我的问题的答案:)

假设我们有以下课程:

public class MyClass
{
   private const string conString = "connection string";

   private int Operation()
   {
      int count = 0;

      using(var con = SqlConnection(conString))
      {
         string select_cmd = "SELECT * FROM TABLE";

         using(var cmd = new SqlCommand(select_cmd, con))
         {
            using(var reader = cmd.ExecuteReader())
            {
               while(reader != null && reader.Read())
                  count++;
            }
         }
      }

      return count;
   }

}

由于在using语句中实例化了与数据库的连接,因此将调用con.close()和最终的con.dispose()方法,是否需要为MyClass实现IDisposable?当MyClass超出范围时,它会被垃圾收集吗?

修改

感谢您的回复,这就是我的想法,但我需要说清楚。还有一个问题。

如果我的类有多个Operations()在数据库上做一些工作,从资源消耗的角度来看,有一个更好的做法是拥有一个SqlConnection成员,instanciate并在类构造函数上打开它并实现IDisposable关闭它不是在每个操作中使用“using”语句(在每个操作上打开和关闭数据库)? 当然,我只应该在使用语句中实例化和使用MyClass对象。

3 个答案:

答案 0 :(得分:3)

不,如果您的类在Operation()方法之外保留SqlConnection实例,那么您只需要实现IDisposable,这样它就可以与类本身一起保持活动状态(例如,如果您将它分配给类会员领域或财产)。

在您的类超出范围之前,SqlConnection实例将被标记为有资格进行清理,因为该实例超出了使用块中的范围。最重要的是,通过Dispose调用释放了非托管数据库连接(由SqlConnection封装)。当GC感到有足够的压力来证明GC通过时,将释放SqlConnection的托管部分。

至于你的类实例,它也将由GC自行决定释放,除非你在整个生命周期中创建和销毁你的类的大量实例,否则你不必担心这个问题。你的应用程序(数百万我猜)。

修改

对于第二个问题,最好每个方法使用和配置SqlConnection实例,因为这个特定的数据库客户端类在内部实现了连接池(即:当你将它处理一段时间时,它并没有真正关闭连接,所以当创建新的SqlConnection时,它会从打开的连接池中重用一个。)

请参阅(旧但有效):http://msdn.microsoft.com/en-us/library/8xx3tyca%28v=vs.71%29.aspx

如果您使用的数据库客户端API没有实现自己的池,那么最好按照您的建议手动管理它。但是,您必须小心同步对连接的访问​​(即:不要让2个线程同时使用它)并自己管理生命周期问题(例如:如果您的类在应用程序的所有持续时间内保持活动状态,那么' ll无限期地打开数据库资源......等等。

大多数现代版本(MySql Connector.NET,SQL Server)都实现了池化。

答案 1 :(得分:1)

Operation()完成后,将释放该方法中使用的所有非托管资源。它没有理由实施IDisposableMyClass不会保持任何非托管资源的开放,因此不需要实现该接口。

关于第二个问题,您的类的实例将像任何其他托管对象一样收集垃圾。

答案 2 :(得分:0)

不,没有必要实现到IDisposable接口,你没有资源可以释放。