编写高质量代码改善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:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...
随机推荐
- bzoj 1044 [HAOI2008]木棍分割——前缀和优化dp
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044 前缀和优化. 但开成long long会T.(仔细一看不用开long long) #i ...
- liunx基础(5)
第十三单元 硬盘分区.格式化及文件系统的管理二 1. 文件系统的挂载与卸载(详见linux系统管理P406)1) 掌握挂载的定义:挂载指将一个设备(通常是存储设备)挂接到一个已存在的目录上.2) 掌握 ...
- go基本数据类型与运算符
GO基本类型1.布尔(bool) 长度:1字节 取值范围:true,false 注意事项:不可用数字代表true或false2.整型(int/uint) 根据平台 肯能为32位或64位3. 8位整型: ...
- php中的move_uploaded_file
1.定义和用法 move_uploaded_file() 函数将上传的文件移动到新位置. 若成功,则返回 true,否则返回 false. 2.语法 move_uploaded_file(file,n ...
- python开发mysql:索引
一,索引管理 索引分类: 普通索引INDEX:加速查找 唯一索引: -主键索引PRIMARY KEY:加速查找+约束(不为空.不能重复) -唯一索引UNIQUE:加速查找+约束(不能重复) 联合索引: ...
- proc文件系统详解(原创)
Linux系统上的/proc目录是一种文件系统,即proc文件系统.与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过 ...
- C# 通用类型转换方法
在程序开发过程中经常需要进行数据的类型转换,而且如果一个字段的类型改成另一个类型时,所有相关的类型转换的地方都要跟着修改,不但造成了很多重复转换的代码而且修改字段类型时额外修改相关转换代码的工作量也很 ...
- Proxmark3笔记(一)
Kali下使用Proxmark3 apt-get update apt-get install build-essential libreadline5 libreadline-dev libusb- ...
- python写一个能生成三种一句话木马的脚本
代码: import time import os from threading import Thread import optparse def aspyijuhua(): try: juy=op ...
- 【树莓派智能门锁】使用脚本控制GPIO来开锁【4】
假定你已经通过此文章或者其他方式完成了树莓派的基本配置 [树莓派]RASPBIAN镜像初始化配置 我们通过VNC View连接到树莓派查看一下~ 1.更新一下基本的设置:更新一下源,把python-d ...