非托管资源、可识别和自定义类型

本文关键字:识别 自定义 类型 资源 | 更新日期: 2023-09-27 18:32:02

关于

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

假设我们有以下类:

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 成员,在类构造函数上实例化并打开它并实现 IDisposable 来关闭它而不是在每个操作中使用"using"语句(在每个操作上打开和关闭数据库)?当然,这样我应该只在 using 语句中实例化和使用 MyClass 对象。

非托管资源、可识别和自定义类型

不,只有当你的类在 Operation() 方法之外保留 SqlConnection 实例时,你才需要实现 IDisposable,这样它与类本身保持活动状态(例如,如果你正在将其辅助到类成员字段或属性)。

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

至于你的类实例,

它也将由 GC 自行决定释放,这是你不需要关心的事情,除非你在应用程序的生命周期中创建和销毁你的类的大量实例(我想是数百万)。

编辑

对于第二个问题,最好使用和释放每个方法的 SqlConnection 实例,因为此特定的数据库客户端类在内部实现连接池(即:当您释放连接一段时间时,它不会真正关闭连接,因此当创建新的 SqlConnection 时,它会重用打开连接池中的一个)。

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

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

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

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

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

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