第七节:使用实现了dispose模式的类型
知道类型如何实现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模式的类型的更多相关文章
- delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行
第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行 以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...
- 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 ...
- CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第七节
第七节:使用下一代CUDA硬件,快乐加速度 原文链接 Rob Farber 是西北太平洋国家实验室(Pacific Northwest National Laboratory)的高级科研人员.他在多个 ...
- 【C# .Net GC】清除非托管类型(Finalize终结器、dispose模式以及safeHandler)
总结 1.一般要获取一个内核对象的引用,最好用SafeHandle来引用它,这个类可以帮你管理引用计数,而且用它引用内核对象,代码更健壮 2.托管中生成并引用非托管,一但非托管和托管中的引用断开(托管 ...
- C#中标准Dispose模式的实现与使用(条目17 实现标准的销毁模式)
实现了Dispose模式与实现了IDisposable接口的区别就是:IDisposable的实现的可靠性(释放相关资源)要靠编程人员来解决(你确信你从来都一直调用了Dispose(Close)方法吗 ...
- [学习笔记] Dispose模式
Dispose模式是.NET中很基础也很重要的一个模式,今天重新复习一下相关的东西并记录下来. 什么是Dispose模式? 什么时候我们该为一个类型实现Dispose模式 使用Dispose模式时应该 ...
- 基于Extjs的web表单设计器 第七节——取数公式设计之取数公式的使用
基于Extjs的web表单设计器 基于Extjs的web表单设计器 第一节 基于Extjs的web表单设计器 第二节——表单控件设计 基于Extjs的web表单设计器 第三节——控件拖放 基于Extj ...
- C#中标准Dispose模式的实现
http://www.cnblogs.com/luminji/archive/2011/03/29/1997812.html 需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个 ...
- JAVA 从GC日志分析堆内存 第七节
JAVA 从GC日志分析堆内存 第七节 在上一章中,我们只设置了整个堆的内存大小.但是我们知道,堆又分为了新生代,年老代.他们之间的内存怎么分配呢?新生代又分为Eden和Survivor,他们的比 ...
随机推荐
- WIN7上搭建Windows Phone 8 开发环境——VMware Workstation下Win8 “无法安装Hyper-V, 某个虚拟机监控程序正在运行”问题解决的办法
最近在试着在Windows 7上搭建Windows Phone 8的开发调试环境,使用的是VMware Workstation + Win8 Pro的虚拟环境, 在漫长的WPexpress_full下 ...
- Python和Django在Windows上的环境搭建
作为一个.NET程序员,真心不喜欢Python以及PHP这种松散的语法.有人说,程序员应该多学几门语言,本想学习Java,无奈感觉Java的语法太啰嗦了.很多人都推荐Python,说它的语法简洁,执行 ...
- 【翻译习作】 Windows Workflow Foundation程序开发-第一章02
1.2 Windows Workflow概览 微软的Windows Workflow Foundation(简称WF)是.NET框架3.0版的一部分..NET3.0其它主要部分是Window ...
- android 3D旋转效果实现
一说到3D,可能第一反应就是使用OpenGL ES....但是,实现这么个小功能,要动用这玩意,莫名的恐惧啊!!!!至今也没弄明白这个怎么玩... 好吧,幸亏还有个Camera类可以帮助我们,据说底层 ...
- centos系统自动化安装研究
https://rhinstaller.github.io/anaconda/intro.html https://github.com/rhinstaller/pykickstart/blob/ma ...
- js中字符串,数字之间转换的常用方法
var number={ num:, num1:"2你好" }; //将数字转换为字符串 var str=number.num.toString();//十进制 );//二进制 ) ...
- Java语法细节(2)
1.逻辑运算符 &和&&,|和||的区别 &&:和&的结果是一样的,但运算过程有区别 &&:只要左边结果为假,就不再执行右边的,结果为假 ...
- 关于解决pyinstaller2.1将.py打包成exe文件在中文目录下不能执行的问题
关于解决pyinstaller2.1将.py打包成exe文件在中文目录下不能执行的问题 这个问题困扰我好久了,今天终于非常偶然的在http://www.v2ex.com/t/113856#reply1 ...
- 一、Struts2的概述
一.Struts2概述 是什么? Struts2是一个M(模型---域--范围模型)V(View视图)C(控制器)框架(模型2).框架都是一个半成品.提高开发效率. Struts1是一个MVC框架,非 ...
- ADO.NET中的Command详解
Command方法介绍 1.ExecuteNonQuery 对于Update.Insert.Delete执行并返回受影响行数 对于其他语句返回 -1 2.ExecuteScalar 执行查询.并返回结 ...