首先来看MSDN中关于这个接口的说明:

[ComVisible(true)] public interface IDisposable {     // Methods     void Dispose(); }
1.[ComVisible(true)]:指示该托管类型对 COM 是可见的.

2.此接口的主要用途是释放非托管资源。当不再使用托管对象时,垃圾回收器会自动释放分配给该对象的内存。但无法预测进行垃圾回收的时间。另外,垃圾回收器对窗口句柄或打开的文件和流等非托管资源一无所知。将此接口的Dispose方法与垃圾回收器一起使用来显式释放非托管资源。当不再需要对象时,对象的使用者可以调用此方法。

一:基本应用

1.我们来定义一个实现了IDisposable接口的类,代码如下:

 public class CaryClass :IDisposable
{     public void DoSomething()     {        Console.WriteLine("Do some thing....");     }     public void Dispose()     {        Console.WriteLine("及时释放资源");     }  }
2.我们有两种方式来调用:
2.1.第一种方式,使用Using语句会自动调用Dispose方法,代码如下:
  using (CaryClass caryClass = new CaryClass())   {       caryClass.DoSomething();   }
2.2第二种方式,现实调用该接口的Dispose方法,代码如下:
  CaryClass caryClass = new CaryClass();    try     {        caryClass.DoSomething();                    }    finally     {        IDisposable disposable = caryClass as IDisposable;        if (disposable != null) disposable.Dispose();     }
两种方式的执行结果是一样的,如下图:
 
2.3.使用try/finally 块比使用 using 块的好处是即使using中的代码引发异常,CaryClass的Dispose方法仍有机
会清理该对象。所以从这里看还是使用try/catch好一些。

二:Disposable 模式
1.在.NET种由于当对象变为不可访问后将自动调用Finalize方法,所以我们手动调用IDisposable接口的Dispose方法
和对象终结器调用的方法极其类似,我们最好将他们放到一起来处理。我们首先想到的是重写Finalize方法,如下:
protected override void Finalize() {      Console.WritleLine("析构函数执行..."); }
当我们编译这段代码的时候,我们发现编译器会报如下的错误:
 
这是因为编译器彻底屏蔽了父类的Finalize方法,编译器提示我们如果要重写Finalize方法我们要提供一个析构函数来
代替,下面我们就提供一个析构函数:
  ~CaryClass()   {       Console.WriteLine("析构函数执行...");   }
实际上这个析构函数编译器会将其转变为如下代码:
protected override void Finalize() {    try    {      Console.WritleLine("析构函数执行...");    }    finally    {      base.Finalize();    } }
2.然后我们就可以将Dispose方法的调用和对象的终结器放在一起来处理,如下:
public class CaryClass: IDisposable {     ~CaryClass()     {         Dispose();     }     public void Dispose()     {         // 清理资源    }
}
3.上面实现方式实际上调用了Dispose方法和Finalize方法,这样就有可能导致做重复的清理工作,所以就有了下面经典
Disposable 模式:
 private bool IsDisposed=false;    public void Dispose()    {        Dispose(true);        GC.SupressFinalize(this);    }    protected void Dispose(bool Diposing)    {        if(!IsDisposed)        {            if(Disposing)            {               //清理托管资源         }            //清理非托管资源      }        IsDisposed=true;    }    ~CaryClass()    {        Dispose(false);    } 

3.1. SupressFinalize方法以防止垃圾回收器对不需要终止的对象调用 Object.Finalize()。 
3.2. 使用IDisposable.Dispose 方法,用户可以在可将对象作为垃圾回收之前随时释放资源。如果调用了 IDisposable.Dispose 方法,此方法会释放对象的资源。这样,就没有必要进行终止。IDisposable.Dispose 应调用 GC.SuppressFinalize 以使垃圾回收器不调用对象的终结器。 
3.3.我们不希望Dispose(bool Diposing)方法被外部调用,所以他的访问级别为protected 。如果Diposing为true则释放托管资源和非托管资源,如果 Diposing等于false则该方法已由运行库从终结器内部调用,并且只能释放非托管资源。 
3.4.如果在对象被释放后调用其他方法,则可能会引发 ObjectDisposedException。

三:实例解析

1.下面代码对Dispose方法做了封装,说明如何在使用托管和本机资源的类中实现 Dispose(bool) 的常规示例:
public class BaseResource : IDisposable     {         // 非托管资源         private IntPtr handle;         //托管资源         private Component Components;         // Dispose是否被调用         private bool disposed = false;          public BaseResource()         {                     }                 public void Dispose()         {             Dispose(true);                         GC.SuppressFinalize(this);         }          protected virtual void Dispose(bool disposing)         {                         if (!this.disposed)                       {                                if (disposing)                 {                     // 释放托管资源                     Components.Dispose();                 }                 // 释放非托管资源,如果disposing为false,                  // 只有托管资源被释放                 CloseHandle(handle);                 handle = IntPtr.Zero;                 // 注意这里不是线程安全的             }             disposed = true;         }          // 析构函数只会在我们没有直接调用Dispose方法的时候调用         // 派生类中不用在次提供析构函数         ~BaseResource()         {             Dispose(false);         }          // 如果你已经调用了Dispose方法后在调用其他方法会抛出ObjectDisposedException         public void DoSomething()         {             if (this.disposed)             {                 throw new ObjectDisposedException();             }         }     }           public class MyResourceWrapper : BaseResource     {         // 托管资源         private ManagedResource addedManaged;         // 非托管资源         private NativeResource addedNative;         private bool disposed = false;                 public MyResourceWrapper()         {                    }          protected override void Dispose(bool disposing)         {             if (!this.disposed)             {                 try                 {                     if (disposing)                     {                                                 addedManaged.Dispose();                     }                                          CloseHandle(addedNative);                     this.disposed = true;                 }                 finally                 {                                        base.Dispose(disposing);                 }             }         }     }

2.使用CLR垃圾收集器,您不必再担心如何管理对托管堆分配的内存,不过您仍需清理其他类型的资源。托管类通过 
IDisposable 接口使其使用方可以在垃圾收集器终结对象前释放可能很重要的资源。通过遵循 disposable 模式并且留 
意需注意的问题,类可以确保其所有资源得以正确清理,并且在直接通过 Dispose 调用或通过终结器线程运行清理代码时 
不会发生任何问题。

本文转自94cool博客园博客,原文链接:http://www.cnblogs.com/94cool/archive/2012/11/21/2780762.html,如需转载请自行联系原作者

.NET中IDisposable接口的基本使用相关推荐

  1. C#中IDisposable 回收非托管资源

    C#中IDisposable 更多2014/9/7 来源:C#学习浏览量:4185 学习标签: IDisposable 本文导读:C#中IDisposable接口的主要用途是释放非托管资源.当不再使用 ...

  2. IDisposable 接口介绍

    定义一种释放分配的非托管资源的方法. 实现 IDisposable 的类 类 说明 AsymmetricAlgorithm 表示所有不对称算法的实现都必须从中继承的抽象基类. BinaryReader ...

  3. 利用IDisposable接口构建包含非托管资源对象

    托管资源与非托管资源 在.net中,对象使用的资源分为两种:托管资源与非托管资源.托管资源由CLR进行管理,不需要开发人员去人工进行控制,.NET中托管资源主要指"对象在堆中的内存" ...

  4. C#知识点总结系列:2、C#中IDisposable和IEnumerable、IEnumerator

    C#中如何合理的释放非托管内存?在本文中我们将讲解使用IDisposable释放托管内存和非托管内存. A.首先需要让类实现IDisposable接口,然后实现IDispose方法. A.a核心Dis ...

  5. 正确使用IDisposable接口

    通过阅读Microsoft文档 ,我知道IDisposable接口的"主要"用途是清理非托管资源. 对我来说,"非托管"意味着诸如数据库连接,套接字,窗口句柄之 ...

  6. C++中的接口(抽象类)

    1.Cpp中的接口(抽象类) 接口描述了类的行为和功能,而不需要完成类的特定实现.接口是使用抽象类来实现的,抽象类与数据抽象互不混淆,数据抽象是一个把实现细节与相关的数据分离开的概念.如果类中至少有一 ...

  7. Java中实现接口与继承的区别

    ** Java中实现接口与继承的区别 ** 首先,先来了解一下什么是接口和继承.接口一般是使用interface来定义的.接口定义同类的定义类似,分为接口的声明和接口体,其中接口体由常量定义和方法定义 ...

  8. Objective-C 入门(七)协议 protocol(JAVA中的接口)

    Objective-C 入门(七)协议 protocol(JAVA中的接口) 接口的作用想必大家都比较了解 OV中的 protocol 相比接口作用相似 语法稍有不同 1.先来看声明一个协议 在创建文 ...

  9. Android中Parcelable接口用法

    --  通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象.也可以将Parcel看成是一个流,通过writeToPa ...

最新文章

  1. 将shp导入SDE中出现“表或视图不存在”问题
  2. 拥抱 Node.js 8.0,N-API 入门极简例子
  3. H3 BPM微信接入配置
  4. MySQL · 引擎特性 · InnoDB 崩溃恢复过程
  5. arm-linux 交叉编译后程序,ARM交叉编译下,应用程序实践
  6. php html标签闭合,php截取字符串,完美html自动闭合
  7. 不来这里买器件?亏大发了!
  8. 01.微服务系列介绍
  9. python列表元组_Python列表元组操作
  10. 未来的经销商还有哪些生意能做?
  11. 刚接触Cisco认证:CCNA学习经验
  12. centos oracle 修改监听服务名_Oracle-Oracle DB、监听和oem开机启动
  13. Linux中DHCP主配置文件解析
  14. diff与patch操作
  15. 基于SSM车牌识别停车场管理系统
  16. 从古代遗传下来的设计值得一看!
  17. 论OSPF中ASBR和ABR
  18. redmi k60参数 红米k60怎么样 redmi k60优缺点
  19. 【数据库】国土空间规划数据库(全域)_模板空库
  20. 高通 qca-wifi 移植

热门文章

  1. cas无法使用_并发编程中cas的这三大问题你知道吗?
  2. java 图片传输方式_Java图像传输方法
  3. mysql server 5.6使用_关于MySQLServer5.6配置问题
  4. RabbitMQ (三)消息重试
  5. android webview 填充,从Android使用WebView自动填充表格
  6. php经典100例,php趣味100例 - php天平称物
  7. oracle开发数据库试题,Oracle_开发数据库试题.doc
  8. 利用WiFi模块实现MicroPython远程开发
  9. 时间到,考试结束。请同学们交卷......
  10. 连续三天说一个事情 : 信号转换