IDisposable
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接口,我们其实应该这样做:
实现Dispose方法;
提取一个受保护的Dispose虚方法,在该方法中实现具体的释放资源的逻辑;
添加析构函数;
添加一个私有的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相关推荐
- IDisposable实现的方法什么时候被执行的
一,以什么是GC所认为的垃圾? 不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收 二,在仓储设计中,我们都知道非托管资源的手动释放,但继承的IDisposa ...
- .NET中IDisposable接口的基本使用
首先来看MSDN中关于这个接口的说明: [ComVisible(true)] public interface IDisposable { // Methods void Dispose(); } 1 ...
- Design Pattern IDisposable Pattern C
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! // - ...
- 强制回收和IDisposable.Dispose方法
如果某对象的 Dispose 方法被调用一次以上,则该对象必须忽略第一次调用后的所有调用. 如果对象的 Dispose 方法被多次调用,该对象一定不要引发异常. 除Dispose 之外的实例方法在资源 ...
- HttpApplication IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable ps url System.Web.dll
// 摘要:// 定义 ASP.NET 应用程序中的所有应用程序对象共有的方法.属性和事件.此类是用户在 Global.asax 文件中所定义的应用程序的基类.[ToolboxItem(false)] ...
- IDisposable 接口介绍
定义一种释放分配的非托管资源的方法. 实现 IDisposable 的类 类 说明 AsymmetricAlgorithm 表示所有不对称算法的实现都必须从中继承的抽象基类. BinaryReader ...
- .Net高级技术——IDisposable
IDisposable概述 GC(垃圾收集器)只能回收托管(Managed)内存资源,对于数据库连接.文件句柄.Socket连接等这些资源(非托管资源,UnManaged)就无能为例,必须程序员自己控 ...
- 【转载自codeproject】Another Look At IDisposable
少了一些图片,我懒得拷了,大家还是去源地址看吧 http://www.codeproject.com/KB/cs/idispose.aspx 极力推荐!!!! Introduction This is ...
- 通过IEnumerable和IDisposable实现可暂停和取消的任务队列
一般来说,软件中总会有一些长时间的操作,这类操作包括下载文件,转储数据库,或者处理复杂的运算. 一种处理做法是,在主界面上提示正在操作中,有进度条,其他部分不可用.这里带来很大的问题, 使用者不知道到 ...
- [分享]另一种对 IDisposable 的实现
相比于刚发出来没多久的关于 MVVM 的文章,对 IDisposable 接口的讨论更是老生常谈了. 详细讲解 IDisposable 的文章也有很多,不想深入了解的看了会头晕,想深入了解的估计也早就 ...
最新文章
- python如何调用参数配置文件_python参数设置
- short 类型的大小为( )个字节。_2008-2012,张一鸣在豆瓣书影音为字节跳动埋下的5个彩蛋...
- 【PC工具】几个电脑录屏相关软件,手机投屏电脑,电脑显示手机摄像头图像,必须好用无广告!...
- 模板技巧之:费用科目条件过滤
- 不修条地铁,都不好意思叫自己大城市
- TMaskEdit组件的简单应用
- verilog学习记(tinyriscv mcu设计)
- Linux下NTP时间同步客户端配置
- PMP-36项目风险管理
- Python爬虫学习笔记 (11) [初级] 小练习 爬取Eason所有歌曲歌词 制作词云图
- 虚幻引擎图文笔记:使用布料模拟(Cloth Simulation)系统制作一面可以随风飘动的旗帜(更新)
- python动态捕捉屏幕_如何使用Python实现自动化截取Windows系统屏幕
- mysql my.cnf 内容_为何 my.cnf 内容是空的,数据库却可以运行
- 钢琴曲欣赏[Beyond]
- 使用Adobe Acrobat设置pdf的页码
- 性能测试的能力验证和规划能力
- 如何把图片pdf转换成txt
- Lucene6.6的介绍和使用
- html表白画画,七夕表白简笔画怎么画?七夕表白简笔画教程
- 正则表达式在线练习网站与资料