建议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模式中应提取一个受保护的虚方法的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议

    1.使用StringBuilder或者使用string.Format("{0}{1}{2}{3}", a, b, c, d)拼接字符串. 2.使用默认转型方法,比如使用类型内置的P ...

  2. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  3. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  4. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  5. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  6. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

  7. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  8. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  9. 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释

    建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...

随机推荐

  1. 转JMeter 利用Jmeter批量数据库插入数据

    1.   启动Jmeter 2.   添加 DBC Connection Configuration 右键线程组->添加->配置元件->JDBC Connection Configu ...

  2. spring mvc静态资源访问的配置

    如果我们使用spring mvc来做web访问请求的控制转发,那么默认所有访问都将被DispatcherServlet独裁统治.比如我现在想访问的欢迎页index.html根本无需任何业务逻辑处理,仅 ...

  3. 安装appium需要注意的事项

    参考 虫师 的博客园  :http://www.cnblogs.com/fnng/p/4560298.html 1.其中第二篇中,打开命令行用的不是windows中的cmd打开的界面,而是用node. ...

  4. Centos 6.5 安装Oracle 11g R2 on vbox

    由于上一篇的rac安装,截图较多,这一篇选择以txt的方式叙述,另外上一篇的时间比较久远,这里最近从新安装 --2018-10-29 1 os环境初始化 [root@rac1 yum.repos.d] ...

  5. SQL Server 2008怎么自动备份数据库

    在SQL Server 2008数据库中.为了防止数据的丢失我们就需要按时的来备份数据库了.要是每天都要备份的话,人工备份会很麻烦的,自动备份的话就不需要那么麻烦了,只 要设置好了,数据库就会自动在你 ...

  6. CVE-2017-11882复现配合koadic

    项目地址:https://github.com/iBearcat/CVE-2017-11882 首先开启koadic,然后配置一下 复制这句代码 mshta http://192.168.220.13 ...

  7. js的console你知道多少

    js的console你知道多少? 列出所有的console属性 console.dir(console) 或者 console.dirxml(console) 记录代码执行时间 console.tim ...

  8. cs231n神经网络 常用激活函数

    CS231n课程笔记翻译:神经网络笔记1(上) 一.常用激活函数 每个激活函数(或非线性函数)的输入都是一个数字,然后对其进行某种固定的数学操作.下面是在实践中可能遇到的几种激活函数: ——————— ...

  9. table td 实现细边框的样式

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org ...

  10. Ubuntu下编写C语言程序

    新建C文件,新建一个文件用touch,新建文件夹用mkdir. 打开文本编辑器,编辑C文件,命令用gedit xxx.C 编写C程序,Ctrl+S保存 编译运行 1.gcc命令是编译 -o是可选项 是 ...