C#/.NET 中推荐的 Dispose 模式的实现

C#/.NET 中推荐的 Dispose 模式的实现

发布于 2015-02-05 02:10 更新于 2018-06-13 03:02

如果你觉得你的类需要实现 IDisposable 接口,还是需要注意一些坑的。不过前人准备了 Dispose 模式 供我们参考,最大程度避免这样的坑。


C#程序中的 Dispose 方法,一旦被调用了该方法的对象,虽然还没有垃圾回收,但实际上已经不能再使用了。所以使用上要仔细考虑细节。

需要明确一下 C# 程序(或者说 .NET)中的资源。简单的说来,C# 中的每一个类型都代表一种资源,而资源又分为两类:

  • 托管资源:由 CLR 管理分配和释放的资源,即由 CLR 里 new 出来的对象;
  • 非托管资源:不受 CLR 管理的对象,Windows 内核对象,如文件、数据库连接、套接字、COM 对象等;

毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口 IDisposable。这相当于是告诉调用者,该类型是需要显式释放资源的,你需要调用我的 Dispose 方法。

不过,这一切并不这么简单,一个标准的继承了 IDisposable 接口的类型应该像下面这样去实现。这种实现我们称之为 Dispose 模式:

public class DisposableObject : IDisposable
{
    /// <summary>
    /// 获取或设置一个值。该值指示资源已经被释放。
    /// </summary>
    private bool _disposed;
  
    /// <summary>
    /// 执行与释放或重置非托管资源相关的应用程序定义的任务。
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
  
    /// <summary>
    /// 关闭此对象使用的所有资源。
    /// </summary>
    public void Close()
    {
        Dispose();
    }
  
    /// <summary>
    /// 由终结器调用以释放资源。
    /// </summary>
    ~DisposableObject()
    {
        Dispose(false);
    }
  
    /// <summary>
    /// 执行与释放或重置非托管资源相关的应用程序定义的任务。
    /// 派生类中重写此方法时,需要释放派生类中额外使用的资源。
    /// </summary>
    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;
    }
}

本文会经常更新,请阅读原文: https://walterlv.com/post/recommended-dispose-implementation.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据小魔方

左手用R右手Python系列16——XPath与网页解析库

最近写了不少关于网页数据抓取的内容,大多涉及的是网页请求方面的,无论是传统的RCurl还是新锐大杀器httr,这两个包是R语言中最为主流的网页请求库。 但是整个...

35550
来自专栏眯眯眼猫头鹰的小树杈

猫头鹰的深夜翻译:Volatile的原子性, 可见性和有序性

为什么要额外写一篇文章来研究volatile呢?是因为这可能是并发中最令人困惑以及最被误解的结构。我看过不少解释volatile的博客,但是大多数要么不完整,要...

17350
来自专栏机器学习实践二三事

Theano的一个关于signal,signal/conv,signal/downsample的错误

安装了Theano和keras之后,准备走段代码出错了,大概意思是: “Theano is missing signal”,就是说signal模块找不到,我跑...

26380
来自专栏CSDN技术头条

QtQuick 系列教程之 QML 与 C++ 交互

QML 作为一种灵活高效的界面开发语言已经越来越得到业界的认可。QML 负责界面,C++ 负责逻辑,这也是 Qt 官方推荐的开发方式。那么 QML 与 C++ ...

28430
来自专栏个人随笔

深入.NET框架

1.1 .NET框架的优点   面向对象   对Web应用的强大支持   对Web Service(Web服务)的支持   实现SOA,支持云计算   支持构建...

306100
来自专栏前端大白专栏

react dva如何获取被form包裹的子组件函数

39190
来自专栏智能大石头

多线程带智能采集策略的采集系统

    去年年底的时候曾经发过一个数据采集器《网页数据采集器》,那是专门针对某一个网站来进行采集的,如果需要采集新的网站内容,就需要修改代码并重新编译。    ...

23280
来自专栏walterlv - 吕毅的博客

如何实现一个可以用 await 异步等待的 Awaiter

发布于 2017-10-29 08:38 更新于 2017-10...

13120
来自专栏程序员的SOD蜜

移花接木:当泛型方法遇上抽象类----我的“内存数据库”诞生记

之前,不怕“重复发明轮子”的我,搞了一个“PDF.NET框架”,即“PWMIS数据开发框架”(目前已经开源),自己用特殊的方式设计了一个实体类基类,然后又设计了...

47250
来自专栏FreeBuf

适用于IDA Pro的CGEN框架介绍

一切都始于我想要分析一些MeP代码的时候。我通常在IDA Pro中做逆向工作,但是有一小部分处理器IDA并不支持。幸运的是,objdump可以支持这些小众的处理...

25170

扫码关注云+社区

领取腾讯云代金券