编写高质量代码改善C#程序的157个建议——建议49:在Dispose模式中应提取一个受保护的虚方法
建议49:在Dispose模式中应提取一个受保护的虚方法
在标准的Dispose模式中,真正的IDisposable接口的Dispose方法并没有做实际的清理工作,它其实是调用了下面的这个带bool参数且受保护的的虚方法:
/// <summary>
/// 非密封类修饰用protected virtual
/// 密封类修饰用private
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
//省略代码
}
之所以提供这样一个受保护的虚方法,是因为考虑了这个类型会被其他类型继承的情况。如果类型存在一个子类,子类也许会实现自己的Dispose模式。受保护的虚方法用来提醒子类:必须在自己的清理方法时注意到父类的清理工作,即子类需要在自己的释放方法中调用base.Dispose方法。
public class DerivedSampleClass : SampleClass
{
//子类的非托管资源
private IntPtr derivedNativeResource = Marshal.AllocHGlobal();
//子类的托管资源
private AnotherResource derivedManagedResource = new AnotherResource();
//定义自己的是否释放的标识变量
private bool derivedDisposed = false; /// <summary>
///重写父类Dispose方法
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
if (derivedDisposed)
{
return;
}
if (disposing)
{
// 清理托管资源
if (derivedManagedResource != null)
{
derivedManagedResource.Dispose();
derivedManagedResource = null;
}
}
// 清理非托管资源
if (derivedNativeResource != IntPtr.Zero)
{
Marshal.FreeHGlobal(derivedNativeResource);
derivedNativeResource = IntPtr.Zero;
}
//调用父类的清理代码
base.Dispose(disposing);
//让类型知道自己已经被释放
derivedDisposed = true;
}
} public class SampleClass : IDisposable
{
//演示创建一个非托管资源
private IntPtr nativeResource = Marshal.AllocHGlobal();
//演示创建一个托管资源
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);
} /// <summary>
/// 非密封类修饰用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");
}
//省略
}
} class AnotherResource : IDisposable
{
public void Dispose()
{
}
}
如果不为类提供这个受保护的虚方法,很有可能让开发者设计子类的时候忽略掉父类的清理工作。所以要在类型的Dispose模式中提供一个受保护的虚方法。
转自:《编写高质量代码改善C#程序的157个建议》陆敏技
编写高质量代码改善C#程序的157个建议——建议49:在Dispose模式中应提取一个受保护的虚方法的更多相关文章
- 编写高质量代码改善C#程序的157个建议
1.使用StringBuilder或者使用string.Format("{0}{1}{2}{3}", a, b, c, d)拼接字符串. 2.使用默认转型方法,比如使用类型内置的P ...
- 编写高质量代码改善C#程序的157个建议[1-3]
原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...
- 读书--编写高质量代码 改善C#程序的157个建议
最近读了陆敏技写的一本书<<编写高质量代码 改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...
- 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试
建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...
- 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本
建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...
- 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码
建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...
- 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣
建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...
- 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释
建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...
- 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释
建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...
随机推荐
- 洛谷【P1064】金明的预算方案
浅谈\(DP\):https://www.cnblogs.com/AKMer/p/10437525.html 题目传送门:https://www.luogu.org/problemnew/show/P ...
- PostgreSQL备份
备份与恢复 postgresql自带了两个备份工具: pg_dump:可备份一个指定的database pg_dumpall:可一次性备份所有database数据以及系统全局数据 使用pg_dump ...
- 创建工程常量 (OC中的宏定义)
1.oc创建宏 文件 2.swift创建 常量文件 在swift中, 并非是预编译代码替换, 而是设置全局常量, 简单宏, 直接let 加常量名即可
- springboot成神之——swagger文档自动生成工具
本文讲解如何在spring-boot中使用swagger文档自动生成工具 目录结构 说明 依赖 SwaggerConfig 开启api界面 JSR 303注释信息 Swagger核心注释 User T ...
- sql中left join on where区别剖析
select from tb1 left join tb2 on tb1.xx=tb2.xx and tb2.xxxx=5 先筛选tb2.xxxx=5 再把tb1与筛选后的临时表进行左连接. sele ...
- X11 转发
SecureCRT只支持字符界面,如果要在终端界面能弹出GUI,需要本地安装X11 server,然后服务器讲X11请求forward到本地,即可. x11 server 可以使用Xming, Xma ...
- Linux进阶路线
初级:熟练使用命令.熟悉Shell编程.能配置简单的服务,清楚各类服务相关的配置文件的位置, 能看懂并可修改系统提供的配置脚本(/etc/*.*)把/etc目录下面常用的配置你都搞懂,把 /bin / ...
- 「小程序JAVA实战」 小程序的事件(11)
转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-11/ 我们以前在web开发的时候,web页面也有一些相关的事件,当然小程序要接触屏幕要进行一些点击 ...
- [原创]Mybatis特殊值Enum类型转换器-ValuedEnumTypeHandler
引言 typeHandlers 阅读官方文档 typeHandlers 一节{:target="_blank"} MyBatis 在预处理语句(PreparedStatement) ...
- 你不知道的js异步、作用域、闭包
例题如下: for (var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 0) ...