介绍

自.NET出现以来,最令人困惑的事情之一是Dispose()(来自IDisposable接口)与终结器之间的关系。

最初的想法

最初的想法很简单:垃圾收集器为我们完成内存和资源的清理,因此我们不需要手动管理内存和资源。

实际上,事情变得更加复杂。当我们需要垃圾收集器运行时,它可能不会运行(正如它所说的,它是“不确定的”)。同样的,static字段使对象保持活动状态,并且我们的代码可以与本地代码交互,并且我们需要对对象和内存生命期进行更多控制。

这使得终结器在垃圾收集器运行时释放外部资源,并通过Dispose()方法“尽快”释放任何资源,而无需等待垃圾收集器运行。这就产生了滚雪球的效果,我们改变整个类层次结构来实现模式,通常我们想要控制当资源释放(Dispose()方法和IDisposable接口)以及控制终结器,因为任何“非托管”数据都需要会被释放即使我们(或我们代码的用户)不调用Dispose()。

原始解决方案——Dispose模式

原始的解决方案是Dispose模式。这并不容易,因为它包括:

  • 具有终结器(调用Dispose(false););
  • 具有Dispose()(调用Dispose(true);和GC.SuppressFinalize(this););
  • 具有一个Dispose(bool disposing);重载,其决定了根据disposing真正要做的事情。此重载可能是虚拟的,也可能不是虚拟的,从而增加了模式的复杂性。

Dispose模式的“雪球”效应

必须决定一个物体是否需要是一次性的,这本身就是一个问题。而且Dispose模式与基类和框架的交互确实很差。

如果框架对象可能需要“可预测”的销毁,则意味着我们需要一个Dispose()或类似的方法。但是,作为框架或基类,这也意味着子类中的对象可能具有不受管理的数据,这意味着我们“需要”终结器。

现在,整个模式需要在任何可能有处理非托管数据的子类的基类上使用。

所以,与其简单的说:

public abstract class MyBaseClass:IDisposable
{public virtual void Dispose(){}
}

我们需要改为以下内容:

public abstract class MyBaseClass:IDisposable
{~MyBaseClass(){Dispose(false);}public void Dispose(){GC.SupressFinalize(this);Dispose(true);}protected virtual void Dispose(bool disposing){}
}

请务必注意,在代码的第一段中,Dispose()是virtual。在第二个中,Dispose() 不应该是virtual,而Dispose(bool disposing)需要是virtual...,并且也不应该是公共的,因为它不应该由用户代码调用。

什么是“disposing”?

当我第一次看到带有“dispose”参数的Dispose()方法时,我真的很困惑。已经命名为“Dispose”的方法中的“disposing”是什么?

我真的认为,如果将Dispose模式命名为Release模式,并且我们有一个“isFromManualDispose”参数,那么事情就不会那么混乱了。它将仍然是一个有问题的模式,但是要理解该论点的含义会容易一些。

为什么这个模式被破坏了?

老实说,“破坏”太强了,但是这是我想要吸引读者注意的东西。这很糟糕,因为它取决于太多的方法和概念,而且也令人困惑。这也很令人困惑。即使“它工作”时正确实现,它:

  • 对于新开发者来说很难;
  • 意味着即使整个框架不使用任何不安全的代码,任何框架类都需要使用Dispose(bool)来处理可能的“不安全”数据;
  • 意味着继承那些类的任何人都需要知道如何处理“可恶的” disposing参数;
  • 意味着违反单一责任原则。一个框架类(或只是任何基类)不应处理所有这些“以防万一”需,但是一个子类需要处理。

解决方案:SafeHandles

一段时间之后,Microsoft注意到了这种不良模式,并试图对其进行修复。那是我们得到SafeHandle的时间。

拥有SafeHandle 的整个想法是,我们的类应该只处理托管内存,或者如果确实需要,则处理“安全句柄”,而不是让我们自己的类处理“托管和非托管内存”。它将具有终结器,并且将真正管理非托管数据的生命周期。

我确实认为Microsoft在一开始就对其进行了记录,但是当我试图找到他们的好例子时,我才发现最新的文档,该文档被完全“破坏了”。他们解释为什么SafeHandle是好的,并帮助我们避免坏的Disposable模式,但随后显示一个使用SafeHandle和实现了Dispose模式的类,却没有真正的好处!

阅读文档后,似乎我们现在在硬模式之上有了一个新模式。但这完全是错误的。新模式取代了旧的硬模式。不要添加到它。

对于那些好奇的人,我指的是此页面。

在该页面的源代码中,甚至包含以下注释:

// No finalizer is needed. The finalizer on SafeHandle
// will clean up the MySafeFileHandle instance,
// if it hasn't already been disposed.
// Howerver, there may be a need for a subclass to
// introduce a finalizer, so Dispose is properly implemented here.
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
protected virtual void Dispose(bool disposing)
  • 关于子类引入终结器的注释是Dispose模式的另一个问题。有人认为,在需要终结器之前我们不应该添加终结器,但是如果基类决定使用终结器,则可能会发生两次处置。我们应该避免所有这些混乱;
  • 在该示例中,单词“Howerver”的拼写错误。编辑者,请不要在本文中修复此问题;
  • 他们说“在这里适当地实现了Dispose”,但实际上却忘记了检查disposing参数。当disposing错误时,他们不支持调用_handle.Dispose()。

“新”模式

SafeHandle创建的目的是简化模式。使用SafeHandle时,我们不必担心整个Dispose模式。相反,我们只需要知道我们是否正在实现Dispose()。只是简单的Dispose(),而不是那么古怪的Dispose(bool disposing)。

然后,如果我们正在处理Windows句柄,则使用适当的安全句柄;如果从未处理过某个对象并收集垃圾,则SafeHandle将为我们完成工作。

实际上,这是新的和改进的模式的基础,即使我们没有处理非托管内存或数据的SafeHandl。

不使用SafeHandle时,新模式究竟是什么?

简单规则:

  • Public类不应具有析构函数或Dispose(bool)。如果是一次性的,则只使用标准Dispose()实现IDisposable;
  • 如果他们使用任何可能需要析构函数的数据,则应使用帮助程序类来保存该数据。正是这样的SafeHandle:帮助程序类保存数据并为您处理析构函数(仅此而已)。

在某种程度上,仅此而已。

如何实现一个帮助程序类?

帮助程序类将需要有一个析构函数,并且可能需要一个析构函数Dispose()以允许资源的早期释放。但是这些帮助程序类可以被密封,并避免任何逻辑来处理托管+非托管数据。它们的存在的唯一目的是处理非托管数据的释放,因此无需进行检查。他们不应该做任何其他事情,因为那将是主要类的工作。他们只是简单的帮手。

重新分析问题

  • Dispose模式:

带有Dispose(bool)的类,一个调用Dispose(false)的终结器,一个调用Dispose(true)的Dispose()重载,而且bool disposing使许多开发商不知道是怎么回事,即使他们的类从来不使用非托管的数据。

  • 新模式:

只是一个简单的IDisposable接口实现,如果类需要确定性清除,如果类可以继承,那么它应该是virtual。如果该类使用了任何非托管数据,则使用一个帮助程序类(对于所有非托管数据都可以相同,例如SafeHandle)。就这样。没有disposing这样的参数,也没有奇怪的实现。

默认情况下,当基类和子类不保存非托管数据时,它们将更加简单。他们仍将能够保留非托管数据(如果需要),但是会将这些数据的“发布”委托给助手类。

Dispose(bool disposing)模式被破坏相关推荐

  1. c#中设计器中窗体释放  protected override void Dispose(bool disposing)改写解决部分窗体线程释放不彻底问题

    c#中设计器中窗体释放  protected override void Dispose(bool disposing)改写解决部分窗体线程释放不彻底问题 /// <summary>    ...

  2. 对.Net 垃圾回收的C#编程相关方面(Finalize 和Dispose(bool disposing)和 Dispose())的一些理解体会...

    Finalize 和Dispose(bool disposing)和 Dispose() 的相同点: 这三者都是为了释放非托管资源服务的. Finalize 和 Dispose() 和Dispose( ...

  3. 18.实现标准的Dispose模式

    首先来看MSDN中关于这个接口的说明: [ComVisible(true)] public interface IDisposable { // Methods void Dispose(); } 1 ...

  4. 有关Dispose,Finalize,GC.SupressFinalize函数-托管与非托管资源释放的模式

    //这段代码来自官方示例,删除了其中用处不大的细节using System; using System.ComponentModel;/**** 这个模式搞的这么复杂,目的是:不管使用者有没有手动调用 ...

  5. C#中的Dispose模式

    C#中的资源 在我们的程序中,使用资源后,需要释放.那么在C#中的每一种资源,可以分为两类: - 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: - 非托管资源:不受CLR管理 ...

  6. C# Dispose模式

    目的 为了及时释放宝贵的非托管资源和托管资源,并且保证资源在被 gc 回收的时候可以正确释放资源,同时兼顾执行效率. 必须遵循的事实 1 .  托管资源释放: 由另一线程的 gc 进行释放,当托管的对 ...

  7. 行动力决定了一个人的成败,有想法,就去做! C#的内存管理原理解析+标准Dispose模式的实现

    尽管.NET运行库负责处理大部分内存管理工作,但C#程序员仍然必须理解内存管理的工作原理,了解如何高效地处理非托管的资源,才能在非常注重性能的系统中高效地处理内存. C#编程的一个优点就是程序员不必担 ...

  8. C# Dispose模式详细分析

    C#Dispose模式 目的: 为了及时释放宝贵的非托管资源和托管资源,并且保证资源在被gc回收的时候可以正确释放资源,同时兼顾执行效率 必须遵循的事实: 1 托管资源释放: 由另一线程的gc进行释放 ...

  9. C#Dispose模式

    C#Dispose模式 目的: 为了及时释放宝贵的非托管资源和托管资源,并且保证资源在被gc回收的时候可以正确释放资源,同时兼顾执行效率 必须遵循的事实: 1 托管资源释放: 由另一线程的gc进行释放 ...

  10. dispose 模式 java_C#使用Dispose模式实现手动对资源的释放

    本文实例讲述了C#使用Dispose模式实现手动对资源的释放.分享给大家供大家参考.具体实现方法如下: //单一类的实现 class MyClass : IDisposable { public My ...

最新文章

  1. 五分钟没有操作自动退出_这又是什么骚操作??5只蚂蚁战略配售基金拟增设B类份额,自动赎回退出!!...
  2. vs编译报错C1020: 意外的 #endif
  3. 反码求和校验: 一个数加上自己取反得到的数正是时钟轮盘上最大那个数
  4. python xlrd关闭_Python在工作中的应用
  5. python画图程序有图-Python海龟画图工具绘制叮当猫程序
  6. python合并文件_python把多个文件合并到一个新文件
  7. boost::signals2模块实现显示插槽通过接口传递的示例程序
  8. 前端学习(1540):案例分析
  9. ubuntu设置始终亮屏_ubuntu系统每次启动屏幕都是最大亮度问题的解决方法
  10. 信息学奥赛一本通(1067:整数的个数)
  11. 【Java从0到架构师】SQL 多表查询
  12. [收藏转载]明星软件工程师的十种特质
  13. iOS开发之应用内检测手机锁屏,解锁状态
  14. 非中文正则表达式 php,php判断是不是为中文正则表达式大全(转)
  15. Mir2源码详解之服务端-选择(角色)网关(SelGate)
  16. CPU-显卡-硬盘性能天梯图排行榜源码
  17. 达梦数据库查看表字段VARCHAR类型的长度单位是BYTE还是CHAR
  18. Win系统 - 如何查看电脑开机了多长时间?
  19. 单片机产生可调方波(c语言),为什么我用单片机做的频率可调的方波输出会有尖刺,而且会断...
  20. 字节跳动校招——运维工程师-系统架构岗位面经分享

热门文章

  1. 调用百度地图API与语音API实现简易地图语音导航
  2. 5gh掌上云计算认证不通过_华为云计算认证考试好考吗?我考华为云计算HCIE的经验分享...
  3. 搜集百度关键词的相关网站、生成词云
  4. 前端工程师行业现状怎么样?前景如何?
  5. Profinet 协议
  6. 学习笔记2-面包板的使用
  7. cad重新加载php命令,cad刷新命令是什么?
  8. Word巧用大纲视图 快速重排版面
  9. 创业怎么写商业计划书?
  10. POJO、PO、DTO、DAO、BO、VO需要搞清楚的概念