• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

详解c# 接口IDisposable的用法

c# 搞代码 4年前 (2022-01-09) 19次浏览 已收录 0个评论

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一个对象时,就本文来源gaodaimacom搞#^代%!码&网(会为该对象在堆上分配内存,如果不再被引用,就会回收它们的内存。如果没有实现IDisposable接口的类型对象,垃圾回收器会直接释放对象所占内存;如果实现了,每次创建对象时,CLR会将该对象的一个指针放到终结列表中,垃圾回收器在回收对象前会首先将终结列表中的指针放入一个freachable队列。同时,CLR会分配一个线程管理freachable队列,调用对象终结器,只有此时,对象才会被真正标识为垃圾,并在下一次进行垃圾回收时释放对象所占内存。即:实现IDisposable接口的类型,至少要经过两次垃圾回收才能真正释放掉内存。其中Dispose方法中的GC.SuppressFinalize()方法用于在显示释放资源后,通知垃圾回收器不用再调用终结器(隐式回收)释放资源。

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


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:详解c# 接口IDisposable的用法
喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址