C#中的IDisposable模式用法详解

 更新时间:2014年09月06日 12:02:26   投稿:shichen2014  
这篇文章主要介绍了C#中的IDisposable模式用法,讲述了垃圾资源回收机制的实现,并对比分析了Dispose()方法、~DisposableClass()析构函数、虚方法Dispose(bool disposing)的原理,需要的朋友可以参考下

本文实例讲述了C#中IDisposable模式的用法,针对垃圾资源的回收进行了较为详细的讲解。分享给大家供大家参考之用。具体方法如下:

首先,对于垃圾回收而言,在C#中,托管资源的垃圾回收是通过CLR的Garbage Collection来实现的,Garbage Collection会调用堆栈上对象的析构函数完成对象的释放工作;而对于一些非托管资源,比如数据库链接对象等,需要实现IDisposable接口进行手动的垃圾回收。那么什么时候使用Idisposable接口,以及如何使用呢?

先来参考一下如下代码:

public interface IDisposable
{
  void Dispose();
}
public class DisposablClass : IDisposable
{
  //是否回收完毕
  bool _disposed;
  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
  ~DisposableClass()
  {
    Dispose(false);
  }
  
  //这里的参数表示示是否需要释放那些实现IDisposable接口的托管对象
  protected virtual void Dispose(bool disposing)
  {
    if(_disposed) return; //如果已经被回收,就中断执行
    if(disposing)
    {
      //TODO:释放那些实现IDisposable接口的托管对象
    }
    //TODO:释放非托管资源,设置对象为null
    _disposed = true;
  }
}

Dispose()方法

当需要回收非托管资源的DisposableClass类,就调用Dispoase()方法。而这个方法不会被CLR自动调用,需要手动调用。

~DisposableClass(),析构函数

当托管堆上的对象没有被其它对象引用,GC会在回收对象之前,调用对象的析构函数。这里的~DisposableClass()析构函数的意义在于告诉GC你可以回收我,Dispose(false)表示在GC回收的时候,就不需要手动回收了。

虚方法Dispose(bool disposing)

通过此方法,所有的托管和非托管资源都能被回收。参数disposing表示是否需要释放那些实现IDisposable接口的托管对象。

如果disposings设置为true,就表示DisposablClass类依赖某些实现了IDisposable接口的托管对象,可以通过这里的Dispose(bool disposing)方法调用这些托管对象的Dispose()方法进行回收。

如果disposings设置为false,就表示DisposableClass类依赖某些没有实现IDisposable的非托管资源,那就把这些非托管资源对象设置为null,等待GC调用DisposableClass类的析构函数,把这些非托管资源进行回收。

另外,以上把Dispose(bool disposing)方法设置为protected virtual的原因是希望有子类可以一起参与到垃圾回收逻辑的设计,而且还不会影响到基类。比如有这样的一个子类:

public class SubDisposableClass : DiposableClass
{
  private bool _disposed; //表示是否已经被回收
  protected override void Dispose(bool disposing)
  {
    if(!_disposed) //如果还没有被回收
    {
      if(disposiing) //如果需要回收一些托管资源
      {
        //TODO:回收托管资源,调用IDisposable的Dispose()方法就可以
      }
      //TODO:回收非托管资源,把之设置为null,等待CLR调用析构函数的时候回收
      _disposed = true;
    }
    base.Dispose(disposing);//再调用父类的垃圾回收逻辑
  }
}

在.NET 2.0之前,如果一个对象的析构函数抛出异常,这个异常会被CLR忽略。但.NET 2.0以后,如果析构函数抛出异常就会导致应用程序的崩溃。所以,保证析构函数不抛异常变得非常重要

还有,Dispose()方法允许抛出异常吗?答案是否定的。如果Dispose()方法有抛出异常的可能,那就需要使用try/catch来手动捕获。以下是考虑Dispose()方法有异常可能的写法:

public class DisposableClass : IDisposable
{
  bool _disposed;
  ......
  protected virtual void Dispose(bool disposing)
  {
    if(_disposed) return;
    if(disposing)
    {
      //TODO:调用托管资源的Dispose()方法进行垃圾回收
    }
    try
    {
      _channelFactory.Close(); //关闭的时候可能会有异常
    }
    catch(Exception ex)
    {
      _log.Warn(ex);//记录日志
      try
      {
        _channelFactory.Abort();//丢弃的时候可能会有异常
      }
      catch(Exception cex)
      {
        _log.Warn(cex);//记录日志
      }
    }
    _channelFactory = null;
    _disposed = true;
  }
}

总结:当我们自定义的类及其业务逻辑中引用某些托管和非托管资源,就需要实现IDisposable接口,实现对这些资源对象的垃圾回收。

希望本文所述对大家实现高效率的C#程序设计能够有所帮助。

相关文章

  • C#实现3D效果完整实例

    C#实现3D效果完整实例

    这篇文章主要介绍了C#实现3D效果的方法,结合完整实例形式分析了C#实现文字3D显示效果的具体步骤与相关操作技巧,需要的朋友可以参考下
    2016-08-08
  • C#中DataGridView常用操作实例小结

    C#中DataGridView常用操作实例小结

    这篇文章主要介绍了C#中DataGridView常用操作,以实例形式总结了DataGridView绑定下拉列表、设置默认值、判断复选框是否选中等技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • C#迭代器方法介绍

    C#迭代器方法介绍

    这篇文章主要介绍了C#迭代器方法,可以使用foreach循环语句进行的迭代的方法,称为可迭代方法,或者迭代器方法,方法操作,想了解更多内容得小伙伴可以学习下面文章内容,希望给你的学习带来帮助
    2022-03-03
  • C#实现chart控件动态曲线绘制

    C#实现chart控件动态曲线绘制

    这篇文章主要为大家详细介绍了C#实现chart控件动态曲线绘制,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C# WinForm程序处理后台繁忙导致前台控件假死现象解决方法

    C# WinForm程序处理后台繁忙导致前台控件假死现象解决方法

    这篇文章主要介绍了C# WinForm程序处理后台繁忙导致前台控件假死现象解决方法,本文通过Application.DoEvents()解决这个问题,并讲解了Application.DoEvents()的作用,需要的朋友可以参考下
    2015-06-06
  • c#代码生成URL地址的示例

    c#代码生成URL地址的示例

    这篇文章主要介绍了c#代码生成URL地址的方法,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-04-04
  • 利用lambda表达式树优化反射详解

    利用lambda表达式树优化反射详解

    这篇文章主要给大家介绍了关于如何利用lambda表达式树优化反射的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • C#实现动态加载dll的方法

    C#实现动态加载dll的方法

    这篇文章主要介绍了C#实现动态加载dll的方法,涉及针对动态链接库的灵活操作技巧,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-12-12
  • 浅谈C#中[]的几种用法

    浅谈C#中[]的几种用法

    本文主要介绍了浅谈C#中[]的几种用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • 基于WPF实现视频封面查看器

    基于WPF实现视频封面查看器

    这篇文章主要为大家详细介绍了WPF如何实现视频封面查看器,文中的示例代码讲解详细,对我们学习或工作有一定帮助,感兴趣的小伙伴可以了解一下
    2022-11-11

最新评论