知道类型如何实现dispose模式之后,接下来看一下开发人员怎样使用提供了dispose模式的类型。这里不再讨论前面的SafeHandle类,而是讨论更常用的FileStream类。

可以利用FileStream打开一个文件,从文件中读取字节,向文件中写入字节,并关闭文件。一个FileStream对象在构造时,它会调用Win32 CreateFile函数,函数返回的句柄保存在SafeFileHandle中,然后通过FileStream对象的一个私有字段来维护运载该对象的引用,FileStream还提供了额外的几个属性(例如:Length,Position,CanRead等)和方法(例如:Read,Write,Flush等)。

假设要写代码来创建一个临时文件,并向其中写入一些字节,然后再删除该文件。开始可能会像下面这样写代码:

遗憾的是生成并运行上面的代码,它也许能工作,但是大多数情况下是不能的,问题是File的Delete方法要求Window删除一个仍然打开的文件。所以Delete方法抛出一个IOException异常.

但在某些情况下,文件可能“误打误撞”地被删除!如果另外一个线程不知怎么造成一次垃圾回收,而且这次垃圾回收刚好在调用Write之后、调用Delete之前发生,那么FileStream的SafeFileHandle字段的Finalize方法就会被调用,这回关闭文件,随后Delete操作也能正常运行。发生这种情况的概率非常小,上面代码无法运行的可能性在99%以上。

幸好FileStream实现了Dispose模式,所以可以修改代码来显示额关闭文件。下面是修改之后的源代码:

static void Main(string[] args)

{

Byte[] byteWrite = new Byte[] { 1, 2, 3, 4, 5 };

FileStream fs = new FileStream("Temp.dat", FileMode.Create);

fs.Write(byteWrite, 0, byteWrite.Length);

fs.Dispose();

File.Delete(@"d:\用户目录\我的文档\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\Temp.dat");

}

上面代码唯一的区别是添加了FileStream的dispose方法的调用。Dispose方法的调用接受一个boolen参数的dispose方法,后者在safehandle对象上调用dispose方法,该方法调用win 32的closeHandle函数,造成Windows关闭文件,然后调用File的Delete方法时,Window发现该文件已经关闭,所以成功的删除它。由于FileStream还提供了一个Close方法,所提也可以用Close方法关闭。

注意:Close方法不是dispose类正式的一部分,有的提供了Close方法,有的没有。

需要注意的是,调用Dispose或Close只是为了能在一个确定的事件强迫对象执行清理;这两个方法并不能控制托管堆中的对象所占用的内存的生存期。这意味着即使一个对象已经完成清理,扔可在它上面调用方法。以下代码演示了关闭后调用Write方法,试图想文件写入更多的字节,显示,这个字节再无法写入文件。代码执行时,对Write方法的第二个调用将抛出一个System.ObjectDisposedException异常,并显示以下字符创:无法访问已关闭的文件。

这里不会出现内存的损坏情况,因为FileStream对象的内存依然“健在”。只是在执行了清理之后,对象不能再成功的执行它的方法。

重要提示:我不赞成无脑的调用dispose和close方法。理由是CLR的垃圾回收期已经做得非常好了,理应把工作要给它去做。垃圾回收期知道一个对象何时不再调用应用程序的代码,而且只有到那个时候才会回收,而当应用程序调用dispose或Close方法时,实际实在信誓旦旦的说它知道应用程序在什么时候不需要一个对象,但对于应用程序来说,都不可能知道一个对象在什么时候不需要。

例如:假定在方法A的代码中构造一个新对象,然后将对该对象的引用传给方法B,方法B可能将对该对象的引用保存在某个内部字段变量中(一个根)。然而,方法A并不知道这个情况,它当然可以调用dispose和close方法,但在此之后,其它代码可能试图访问该对象,造成跑出一个ObjectDisposedException。

建议只有在以下这两种情况下才调用dispose或close:确定必须清理资源,或者确定可以安全的调用dispose或close,并希望将对象从终结列表中删除,禁止对象提供到另一代,从而提升性能。

第七节:使用实现了dispose模式的类型的更多相关文章

  1. delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行

    第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行     以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...

  2. centos Linux下磁盘管理 parted,df ,du,fdisk,partprobe,mkfs.ext4,mount,/etc/fstab,fsck,e2fsck,mk2efs,tmpfs ,nr_inodes, LVM,传统方式扩容文件系统 第七节课

    centos Linux下磁盘管理   parted,df ,du,fdisk,partprobe,mkfs.ext4,mount,/etc/fstab,fsck,e2fsck,mk2efs,tmpf ...

  3. CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第七节

    第七节:使用下一代CUDA硬件,快乐加速度 原文链接 Rob Farber 是西北太平洋国家实验室(Pacific Northwest National Laboratory)的高级科研人员.他在多个 ...

  4. 【C# .Net GC】清除非托管类型(Finalize终结器、dispose模式以及safeHandler)

    总结 1.一般要获取一个内核对象的引用,最好用SafeHandle来引用它,这个类可以帮你管理引用计数,而且用它引用内核对象,代码更健壮 2.托管中生成并引用非托管,一但非托管和托管中的引用断开(托管 ...

  5. C#中标准Dispose模式的实现与使用(条目17 实现标准的销毁模式)

    实现了Dispose模式与实现了IDisposable接口的区别就是:IDisposable的实现的可靠性(释放相关资源)要靠编程人员来解决(你确信你从来都一直调用了Dispose(Close)方法吗 ...

  6. [学习笔记] Dispose模式

    Dispose模式是.NET中很基础也很重要的一个模式,今天重新复习一下相关的东西并记录下来. 什么是Dispose模式? 什么时候我们该为一个类型实现Dispose模式 使用Dispose模式时应该 ...

  7. 基于Extjs的web表单设计器 第七节——取数公式设计之取数公式的使用

    基于Extjs的web表单设计器 基于Extjs的web表单设计器 第一节 基于Extjs的web表单设计器 第二节——表单控件设计 基于Extjs的web表单设计器 第三节——控件拖放 基于Extj ...

  8. C#中标准Dispose模式的实现

    http://www.cnblogs.com/luminji/archive/2011/03/29/1997812.html 需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个 ...

  9. JAVA 从GC日志分析堆内存 第七节

    JAVA 从GC日志分析堆内存 第七节   在上一章中,我们只设置了整个堆的内存大小.但是我们知道,堆又分为了新生代,年老代.他们之间的内存怎么分配呢?新生代又分为Eden和Survivor,他们的比 ...

随机推荐

  1. 《Code Complete》ch.8 防御式编程

    WHAT? 主要思想:子程序不应因传入参数错误而被破坏 WHY? 保护程序免遭非法输入的破坏 HOW? 断言 assert denominator != 0 : "denominator s ...

  2. The Ninth Hunan Collegiate Programming Contest (2013) Problem G

    Problem G Good Teacher I want to be a good teacher, so at least I need to remember all the student n ...

  3. java 实例之杨辉三角

    public class study{ public static void main(String args[]){ int i,j,level=7; int Yang[][] = new int[ ...

  4. MFC获取文本框字符串

    //方法1:使用用GetDlgItem,得到控件对像, 再GetWindowText //GetDlgItem(IDC_EDIT1)->GetWindowText() //方法2:控件与对应类关 ...

  5. windows常用运行命令收集(持续更新)

    快捷键打开运行窗口:Windows + R > calc(计算器) > gpedit.msc(本地组策略编辑器) > regedit(注册表) > mstsc(远程桌面) &g ...

  6. selenium借助AutoIt识别上传文件Java篇

    官方网站:https://www.autoitscript.com/site/ 从网站上下载AutoIt并安装,安装完成在菜单中会看到图4.13的目录: 图4.13  AutoIt菜单 1.首先打开A ...

  7. 在Win7下要通过某个 线程 来调用SavaDialog文件选择框的问题

    如果 在Win7下要通过某个 线程 来调用SavaDialog文件选择框的代码  选择窗口 有时会出不来 需要设置如下:    ThreadthreadOfRec = new Thread(Reciv ...

  8. infusion度量金字塔数据解释

    inFusion能够探测超过20中代码味道和代码缺陷,包括重复代码,破坏封装的类(如数据类或者万能类),高耦合的方法和类,以及一些设计不合理的类继承结构.当我们使用inFusion工具分析代码时,在分 ...

  9. WF4 持久化 <第四篇>

    一.基础示例 WF4 默认支持SQLServer的持续化,首先要执行目录C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en下的脚本: SqlPer ...

  10. js中的条件语句

    //js中的条件语句 ; //example1 单分支语句 ){ console.log("你已经不年轻了!"); }else{ console.log("你依然很有活力 ...