IDisposable

MSDN的解释:IDisposable Interface:Provides a mechanism for releasing unmanaged resources(提供释放非托管资源的机制)。

定义一种释放分配的资源的方法。

Dispose

dispose是处理、处置的意思。

IDisposable下面有一个方法:void Dispose();

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources。

执行(与释放或重置非托管资源相关的)应用程序定义的任务。

首先我们需要明确什么是C#(或者说.NET)中的资源,打码的时候我们经常说释放资源,那么到底什么是资源,简单来讲,C#中的每一种类型都是一种资源,而资源又分为托管资源和非托管资源,那这又是什么?!

托管资源:由CLR管理分配和释放的资源,也就是我们直接new出来的对象;

非托管资源:不受CLR控制的资源,也就是不属于.NET本身的功能,往往是通过调用跨平台程序集(如C++)或者操作系统提供的一些接口,比如Windows内核对象、文件操作、数据库连接、socket、Win32API、网络等。

假设我们要使用FileStream,我们通常的做法是将其using起来,或者是更老式的try…catch…finally…这种做法,因为它的实现调用了非托管资源,所以我们必须用完之后要去显式释放它,如果不去释放它,那么可能就会造成内存泄漏(所谓内存泄露就是虽然资源已经用完了,但是资源占用的这块内存一直被占用,不被释放,导致可用内存减少)。

这听上去貌似很简单,但我们编码的时候可能很多时候会忽略掉释放资源这个问题,.NET的垃圾回收又如何帮我们释放非托管资源,接下来我们一探究竟吧,一个标准的释放非托管资源的类应该去实现IDisposable接口:

public class MyClass:IDisposable
{/// <summary>执行与释放或重置非托管资源关联的应用程序定义的任务。</summary>public void Dispose(){}
}

我们实例化的时候就可以将这个类using起来:(mc只在{}中起作用)

using(var mc = new MyClass())
{
}

看上去很简单嘛,但是,要是就这么简单的话,也没有这篇文章的必要了。如果要实现IDisposable接口,我们其实应该这样做:

  1. 实现Dispose方法;

  2. 提取一个受保护的Dispose虚方法,在该方法中实现具体的释放资源的逻辑;

  3. 添加析构函数;

  4. 添加一个私有的bool类型的字段,作为释放资源的标记

接下来,我们来实现这样的一个Dispose模式:

public class MyClass : IDisposable
{/// <summary>/// 模拟一个非托管资源/// </summary>private IntPtr NativeResource { get; set; } = Marshal.AllocHGlobal(100);/// <summary>/// 模拟一个托管资源/// </summary>public Random ManagedResource { get; set; } = new Random();/// <summary>/// 释放标记/// </summary>private bool disposed;/// <summary>/// 为了防止忘记显式的调用Dispose方法/// </summary>~MyClass(){//必须为falseDispose(false);}/// <summary>执行与释放或重置非托管资源关联的应用程序定义的任务。</summary>public void Dispose(){//必须为trueDispose(true);//通知垃圾回收器不再调用终结器GC.SuppressFinalize(this);}/// <summary>/// 非必需的,只是为了更符合其他语言的规范,如C++、java/// </summary>public void Close(){Dispose();}/// <summary>/// 非密封类可重写的Dispose方法,方便子类继承时可重写/// </summary>/// <param name="disposing"></param>protected virtual void Dispose(bool disposing){if (disposed){return;}//清理托管资源if (disposing){if (ManagedResource != null){ManagedResource = null;}}//清理非托管资源if (NativeResource != IntPtr.Zero){Marshal.FreeHGlobal(NativeResource);NativeResource = IntPtr.Zero;}//告诉自己已经被释放disposed = true;}
}

如果不是虚方法,那么就很有可能让开发者在子类继承的时候忽略掉父类的清理工作,所以,基于继承体系的原因,我们要提供这样的一个虚方法。

其次,提供的这个虚方法是一个带bool参数的,带这个参数的目的,是为了释放资源时区分对待托管资源和非托管资源,而实现自IDisposable的Dispose方法调用时,传入的是true,而终结器调用的时候,传入的是false,当传入true时代表要同时处理托管资源和非托管资源;而传入false则只需要处理非托管资源即可。

那为什么要区别对待托管资源和非托管资源?在这个问题之前,其实我们应该先弄明白:托管资源需要手动清理吗?不妨将C#的类型分为两类:一类实现了IDisposable,另一类则没有。前者我们定义为非普通类型,后者为普通类型。非普通类型包含了非托管资源,实现了IDisposable,但又包含有自身是托管资源,所以不普通,对于我们刚才的问题,答案就是:普通类型不需要手动清理,而非普通类型需要手动清理。

而我们的Dispose模式设计思路在于:如果显式调用Dispose,那么类型就该按部就班的将自己的资源全部释放,如果忘记了调用Dispose,那就假定自己的所有资源(哪怕是非普通类型)都交给GC了,所以不需要手动清理,所以这就理解为什么实现自IDisposable的Dispose中调用虚方法是传true,终结器中传false了。

同时我们还注意到了,虚方法首先判断了disposed字段,这个字段用于判断对象的释放状态,这意味着多次调用Dispose时,如果对象已经被清理过了,那么清理工作就不用再继续。

但Dispose并不代表把对象置为了null,且已经被回收彻底不存在了。但事实上,对象的引用还可能存在的,只是不再是正常的状态了,所以我们明白有时候我们调用数据库上下文有时候为什么会报“数据库连接已被释放”之类的异常了。

所以,disposed字段的存在,用来表示对象是否被释放过。

IDisposable相关推荐

  1. IDisposable实现的方法什么时候被执行的

    一,以什么是GC所认为的垃圾? 不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收 二,在仓储设计中,我们都知道非托管资源的手动释放,但继承的IDisposa ...

  2. .NET中IDisposable接口的基本使用

    首先来看MSDN中关于这个接口的说明: [ComVisible(true)] public interface IDisposable { // Methods void Dispose(); } 1 ...

  3. Design Pattern IDisposable Pattern C

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! // - ...

  4. 强制回收和IDisposable.Dispose方法

    如果某对象的 Dispose 方法被调用一次以上,则该对象必须忽略第一次调用后的所有调用. 如果对象的 Dispose 方法被多次调用,该对象一定不要引发异常. 除Dispose 之外的实例方法在资源 ...

  5. HttpApplication IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable ps url System.Web.dll

    // 摘要:// 定义 ASP.NET 应用程序中的所有应用程序对象共有的方法.属性和事件.此类是用户在 Global.asax 文件中所定义的应用程序的基类.[ToolboxItem(false)] ...

  6. IDisposable 接口介绍

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

  7. .Net高级技术——IDisposable

    IDisposable概述 GC(垃圾收集器)只能回收托管(Managed)内存资源,对于数据库连接.文件句柄.Socket连接等这些资源(非托管资源,UnManaged)就无能为例,必须程序员自己控 ...

  8. 【转载自codeproject】Another Look At IDisposable

    少了一些图片,我懒得拷了,大家还是去源地址看吧 http://www.codeproject.com/KB/cs/idispose.aspx 极力推荐!!!! Introduction This is ...

  9. 通过IEnumerable和IDisposable实现可暂停和取消的任务队列

    一般来说,软件中总会有一些长时间的操作,这类操作包括下载文件,转储数据库,或者处理复杂的运算. 一种处理做法是,在主界面上提示正在操作中,有进度条,其他部分不可用.这里带来很大的问题, 使用者不知道到 ...

  10. [分享]另一种对 IDisposable 的实现

    相比于刚发出来没多久的关于 MVVM 的文章,对 IDisposable 接口的讨论更是老生常谈了. 详细讲解 IDisposable 的文章也有很多,不想深入了解的看了会头晕,想深入了解的估计也早就 ...

最新文章

  1. python如何调用参数配置文件_python参数设置
  2. short 类型的大小为( )个字节。_2008-2012,张一鸣在豆瓣书影音为字节跳动埋下的5个彩蛋...
  3. 【PC工具】几个电脑录屏相关软件,手机投屏电脑,电脑显示手机摄像头图像,必须好用无广告!...
  4. 模板技巧之:费用科目条件过滤
  5. 不修条地铁,都不好意思叫自己大城市
  6. TMaskEdit组件的简单应用
  7. verilog学习记(tinyriscv mcu设计)
  8. Linux下NTP时间同步客户端配置
  9. PMP-36项目风险管理
  10. Python爬虫学习笔记 (11) [初级] 小练习 爬取Eason所有歌曲歌词 制作词云图
  11. 虚幻引擎图文笔记:使用布料模拟(Cloth Simulation)系统制作一面可以随风飘动的旗帜(更新)
  12. python动态捕捉屏幕_如何使用Python实现自动化截取Windows系统屏幕
  13. mysql my.cnf 内容_为何 my.cnf 内容是空的,数据库却可以运行
  14. 钢琴曲欣赏[Beyond]
  15. 使用Adobe Acrobat设置pdf的页码
  16. 性能测试的能力验证和规划能力
  17. 如何把图片pdf转换成txt
  18. Lucene6.6的介绍和使用
  19. html表白画画,七夕表白简笔画怎么画?七夕表白简笔画教程
  20. 正则表达式在线练习网站与资料

热门文章

  1. 使用python批量将svg转换成PNG
  2. matlab显示警告:由于未找到因为输出,无法播放音频
  3. RNN-递归神经网络
  4. ei capitan mysql_OSX 10.11 EI Capitan初步上手体验以及开发环境配置
  5. 那些天,一个应届研究生在上海找工作
  6. 1384:珍珠(bead)
  7. 凯立德 C1204-C7P08-3H2RJ22
  8. 在Android Studio中使用Lambda
  9. 原始字符串(Raw String)
  10. Apache的三种MPM模式比较:prefork,worker,event