C#中标准Dis“.NET研究”pose模式的实现
需要明确一下C#程序(或者说.NET)中的资源。简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类:
托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象;
非托管资源:不受CLR管理的对象,windows内核对象,如文件、数据库连接、套接字、COM对象等;
毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口IDisposable。这相当于是告诉调用者,该类型是需要显式释放资源的,你需要调用我的Dispose方法。
不过,这一切并不这么简单,一个标准的继承了IDisposable接口的类型应该像下面这样去实现。这种实现我们称之为Dispose模式:
{
//演示创建一个非托管资源
private IntPtr nativeResource = M上海企业网站制作arshal.AllocHGlobal(100);
//演示创建一个托管资源
private AnotherResource managedResource = new AnotherResource();
private bool disposed = false;
/// <summary>
/// 实现IDisposable中的Dispose方法
/// </summary>
public void Dispose()
{
//必须为true
Dispose(true);
//通知垃圾回收机制不再调用终结器(析构器)
GC.SuppressFinalize(this);
}
/// <summary>
/// 不是必要的,提供一个Close方法仅仅是为了更符合其他语言(如C++)的规范
/// </summary>
public void Close()
{
Dispose();
}
/// <summary>
/// 必须,以备程序员忘记了显式调用Dispose方法
/// </summary>
~SampleClass()
{
//必须为false
Dispose(false);
}
/// <summa上海徐汇企业网站制作ry>
/// 非密封类修饰用protected virtual
/// 密封类修饰用private
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
// 清理托管资源
if (managedResource != null)
{
managedResource.Dispose();
managedResource = null;
}
上海徐汇企业网站设计与制作 }
// 清理非托管资源
if (nativeResource != IntPtr.Zero)
{
Marshal.FreeHGlobal(nativeResource);
nativeResource = IntPtr.Zero;
}
//让类型知道自己已经被释放
disposed = true;
}
public void SamplePublicMethod()
{
if (disposed)
{
throw new ObjectDisposedException("SampleClass", "SampleClass is disposed");
}
//省略
}
}
在Dispose模式中,几乎每一行都有特殊的含义。
在标准的Dispose模式中,我们注意到一个以~开头的方法:
/// 必须,以备程序员忘记了显式调用Dispose方法
/// </summary>
~SampleClass()
{
//必须为false
Dispose(false);
}
这个方法叫做类型的终结器。提供终结器的全部意义在于:我们不能奢望类型的调用者肯定会主动调用Dispose方法,基于终结器会被垃圾回收器调用这个特点,终结器被用做资源释放的补救措施。
一个类型的Dispose方法应该允许被多次调用而不抛异常。鉴于这个原因,类型内部维护了一个私有的布尔型变量disposed:
在实际处理代码清理的方法中,加入了如下的判断语句:
{
return;
}
//省略清理部分的代码,并在方法的最后为disposed赋值为true
disposed = true;
这意味着类型如果被清理过一次,则清理工作将不再进行。
应该注意到:在标准的Dispose模式中,真正实现IDisposable接口的Dispose方法,并没有实际的清理工作,它实际调用的是下面这个带布尔参数的受保护的虚方法:
/// 非密封类修饰用protected virtual
/// 密封类修饰用private
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
//省略代码
}
之所以提供这样一个受保护的虚方法,是为了考虑到这个类型会被其他类继承的情况。如果类型存在一个子类,子类也许会实现自己的Dispose模式。受保护的虚方法用来提醒子类必须在实现自己的清理方法的时候注意到父类的清理工作,即子类需要在自己的释放方法中调用base.Dispose方法。
还有,我们应该已经注意到了真正撰写资源释放代码的那个虚方法是带有一个布尔参数的。之所以提供这个参数,是因为我们在资源释放时要区别对待托管资源和非托管资源。
上海企业网站设计与制作>上海网站建设> 在供调用者调用的显式释放资源的无参Dispose方法中,调用参数是true:
{
//必须为true
Dispose(true);
//其他省略
}
这表明,这个时候代码要同时处理托管资源和非托管资源。
在供垃圾回收器调用的隐式清理资源的终结器中,调用参数是false:
{
//必须为false
Dispose(false);
}
这表明,隐式清理时,只要处理非托管资源就可以了。
那么,为什么要区别对待托管资源和非托管资源。在认真阐述这个问题之前,我们需要首先弄明白:托管资源需要手动清理吗?不妨先将C#中的类型分为两类,一类继承了IDisposable接口,一类则没有继承。前者,我们暂时称之为非普通类型,后者我们称之为普通类型。
非普通类型因为包含非托管资源,所以它需要继承IDisposable接口,但是,这个包含非托管资源的类型本身,它是一个托管资源。所以说,托管资源需要手动清理吗?这个问题的答案是:托管资源中的普通类型,不需要手动清理,而非普通类型,是需要手动清理的(即调用Dispose方法)。
Dispose模式设计的思路基于:如果调用者显式调用了Dispose方法,那么类型就该按部就班为自己的所以资源全部释放掉。如果调用者忘记调用Dispose方法,那么类型就假定自己的所有托管资源(哪怕是那些上段中阐述的非普通类型)全部交给垃圾回收器去回收,而不进行手工清理。理解了这一点,我们就理解了为什么Dispose方法中,虚方法传入的参数是true,而终结器中,虚方法传入的参数是true。
注意:我们提到了需要及时释放资源,却并没有进一步细说是否需要及时让引用等于null这一点。有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾。其他人则认为这没有任何帮助。
C#中标准Dis“.NET研究”pose模式的实现相关推荐
- 英语语言用计算机研究什么软件,高中英语新课程标准词汇习得研究—多媒体计算机辅助语言软件在教学中的应用.doc...
高中英语新课程标准词汇习得研究 -多媒体计算机辅助语言软件在教学中的应用 [摘要]本文根据新颁<普通高中英语课程标准(实验)>(简称高中新课程标准)的精神,探讨如何通过校本教育研究的合作模 ...
- 转载:建设工程中常见的项目建设管理模式有哪些(DBB模式、EPC模式)
原文标题:建设工程中常见的项目建设管理模式有哪些? - 知乎 (zhihu.com) 一.DBB模式 即设计-招标-建造(Design-Bid-Build)模式,这是最传统的一种工程项目管理模式.该管 ...
- [渝粤教育] 江西师范大学 美术课程标准与教材研究 参考 资料
教育 -美术课程标准与教材研究-章节资料考试资料-江西师范大学[] 课程概述 1.[单选题]提出"以美育代宗教"的是谁? A.康德 B.王国维 C.蔡元培 D.鲁迅 参考资料[ ] ...
- 脑影像中的深度学习研究:前景与挑战
深度学习(DL)在应用于自然图像分析时非常成功.相比之下,将其用于神经影像学数据分析时则存在一些独特的挑战,包括更高的维度.更小的样本量.多种异质模态以及有限的真实标签(ground truth).在 ...
- matlab中normcdf函数用法,Matlab中标准正态分布的密度函数是normcdf(x,0,1)
中标准正属于项目资本现金流量表中现金流出构成的是() 态分USCI模块中的波特率由分频器和调制器共同作用生成. 在MSP430F66xx时钟设置中XT1的XIN和XOUT引脚接32768Hz低频晶振, ...
- 文章推荐 | 城市规划中城市信息学的研究进展
来源:北京城市实验室BCL 随着计算机技术的飞速发展,城市信息学作为城市规划领域的一门新兴学科,逐渐引起学术界的关注.城市信息学的兴起给城市规划带来了新的压力,但它也提供了新的城市分析视角.在此背景下 ...
- Linux 中启用 Shell 脚本的调试模式
shell 脚本调试系列 Linux 中启用 Shell 脚本的调试模式 在 Shell 脚本中执行语法检查调试模式 在 Shell 脚本中跟踪调试命令的执行 概述 脚本是存储在一个文件的一系列命令. ...
- 中国产教融合市场发展模式与运营前景咨询报告2022版
中国产教融合市场发展模式与运营前景咨询报告2022版 HS--HS--HS--HS--HS--HS--HS--HS--HS--HS--HS--HS-- [修订日期]:2021年11月 [搜索鸿晟信合研 ...
- android 怎么自定义任务栈,Android中的Activity详解--启动模式与任务栈
目录 Activity 生命周期 任务栈 启动模式 Intent Flag taskAffinity属性 1.Activity activity的简单介绍就不写了,作为最常用的四大组件之一,肯定都很熟 ...
最新文章
- iOS autolayout
- Java学习小程序(10)三个等级的才字母游戏
- win7 + vs2015+ matlab2016a + python3.5安装matcaffe cpu版本
- 女朋友天天气我怎么办_关于我的天气很奇怪
- 第十周学习总结--助教
- [poj 3436]最大流+输出结果每条边流量
- 全中国加油:Github 开源了新型肺炎防疫项目,一起助力
- qca9377linux无线驱动,ubuntu下安装无线网卡去驱动Qualcomm-Atheros-QCA9377
- 华腾java_北大青鸟华腾学校 一个java痴迷者的独白
- Oracle 系列 统计信息详解(Statistic)
- 软件测试 技术类面试题问题集锦
- 【热门主题】蓝色妖姬电脑桌面主题
- 如何建立个人网站?先分享一下
- MyBatis 简单手写的 实现
- iOS Apple登录一些限制与细节
- 一篇编译内核的详细配置文章
- 深读5G发展的趋势后带给我的感受
- 【C】报错[Error] lvalue required as left operand of assignment
- 打印Diamond钻石图案
- 如果今天是生命里的最后一天你想做点啥