欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解c# 接口IDisposable的用法

程序员文章站 2022-03-14 22:15:47
c#的每一个类型都代表一种资源,而资源又分为两类: 托管资源 由clr管理分配和释放的资源,即从clr里new出来的对象。 非托管资源 不受clr管理的对象,如windows内核对象,或者文件、数...

  c#的每一个类型都代表一种资源,而资源又分为两类:

  • 托管资源  由clr管理分配和释放的资源,即从clr里new出来的对象。
  • 非托管资源  不受clr管理的对象,如windows内核对象,或者文件、数据库连接、套接字、com对象等。

  如果类型用到了非托管资源,或者需要显式释放托管资源,那么需要让类型继承接口idisposable。记住:如果类型需要显式释放资源,那么一定要继承idisposable接口。如:

class sampleclass:idisposable
{
  private intptr nativeresource = marshal.allochglobal(100);//非托管资源
  private bitmap bitmap = new bitmap(100, 100);//托管资源
  private bool isdisposed = false;
  
  //实现idisposable中的dispose方法
  public void dispose( )
  {
    dispose(true);
    gc.suppressfinalize(this);//通知垃圾回收器不用再调用终结器
  }
  //不必要的方法,只是为了符合其他语言的规范
  public void close()
  {
    dispose();
  }
  //必须的,防止程序员忘记显示调用dispose方法(隐式清理)
  ~sampleclass()
  {
    dispose(false);
  }
  //非密封类修饰用protected virtual,提醒子类必须实现自己的清理方法时注意到父类的清理工作
  protected virtual void dispose(bool isdisposing)
  {
    if(isdisposed)
    {
      return;
    }
    if(isdisposing)
    {
      //清理托管资源
      if(bitmap != null)
      {
        bitmap.dispose();
        bitmap = null;
      }
    }
    //清理非托管资源
    if(nativeresource!=intptr.zero)
    {
      marshal.freehglobal(nativeresource);
      nativeresource = intptr.zero;
    }
    isdisposed = false;
  }
  
  public void samplepublicmethod()
  {
    if(isdisposed)
    {
      throw new objectdisposedexception("sampleclass", "sampleclass is disposed");
    }
    //代码
  }
}

  继承idisposable接口,可以使用using语法糖。在using语句代码块内,可以使用声明的对象,当语句离开代码块后,系统自动释放资源:

//使用using方法,当语句离开代码块后,using内的对象自动释放
using (sampleclass sample = new sampleclass())
{
  //……
}
//以上代码相当于下面的代码
sampleclass sample0 = new sampleclass();
try
{
  //……
}
finally
{
  sample0.dispose();
}

  在sampleclass中,存在一个终结器(c++中叫析构器)。其意义在于,调用者可能并不会主动调用dispose方法,而终结器会被垃圾回收器调用调用,所以它作为释放资源的补救措施。

  在clr中,每new一个对象时,就会为该对象在堆上分配内存,如果不再被引用,就会回收它们的内存。如果没有实现idisposable接口的类型对象,垃圾回收器会直接释放对象所占内存;如果实现了,每次创建对象时,clr会将该对象的一个指针放到终结列表中,垃圾回收器在回收对象前会首先将终结列表中的指针放入一个freachable队列。同时,clr会分配一个线程管理freachable队列,调用对象终结器,只有此时,对象才会被真正标识为垃圾,并在下一次进行垃圾回收时释放对象所占内存。即:实现idisposable接口的类型,至少要经过两次垃圾回收才能真正释放掉内存。其中dispose方法中的gc.suppressfinalize()方法用于在显示释放资源后,通知垃圾回收器不用再调用终结器(隐式回收)释放资源。

  在实现idisposable接口时,其dispose()方法并没有做实际的清理工作,但提供了带bool参数的受保护的虚方法。因为该类型可能被其他类继承,如果子类实现自己的dispose模式,受保护的虚方法可以提醒子类:在实现自己的清理方法时,需要注意父类的清理工作(base.dispose方法)。

  真正撰写资源释放代码的虚方法有一个bool参数,但是在显示释放资源(true)与隐式释放资源(false)调用中传入的参数不同。表明:隐式清理时,只需要处理非托管资源就行。托管资源中的普通类型不需要手动清理,而非普通类型需要手动清理。

  dispose模式设计思路:如果调用者显示调用了dispose方法,那么类型按部就班释放自己的全部资源,然后通知垃圾回收器不需要再释放(gc.suppressfinalize()方法);而忘记调用dispose方法,那么类型就假定自己的所有托管资源会全部交给垃圾回收器回收,不需要手动清理。

以上就是详解c# 接口idisposable的用法的详细内容,更多关于c# 接口idisposable的用法的资料请关注其它相关文章!