当前位置: 首页 > news >正文

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

如果你觉得你的类需要实现 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;
    }
}

相关文章:

  • Windows 10 四月更新,文件夹名称也能区分大小写?
  • WPF 中使用附加属性,将任意 UI 元素或控件裁剪成圆形(椭圆)
  • XML 的 XPath 语法
  • .NET 使用 XPath 来读写 XML 文件
  • 像黑客一样!Chrome 完全键盘操作指南(原生快捷键 + Vimium 插件)
  • 如何在 .NET 库的代码中判断当前程序运行在 Debug 下还是 Release 下
  • 在制作跨平台的 NuGet 工具包时,如何将工具(exe/dll)的所有依赖一并放入包中
  • WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)
  • 理解 Roslyn 中的红绿树(Red-Green Trees)
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • .NET/C# 使窗口永不获得焦点
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • WPF 应用完全模拟 UWP 的标题栏按钮
  • 让控制台支持 ANSI 转义序列,输出下划线、修改颜色或其他控制
  • 【译】理解JavaScript:new 关键字
  • Android优雅地处理按钮重复点击
  • bearychat的java client
  • codis proxy处理流程
  • Go 语言编译器的 //go: 详解
  • JAVA多线程机制解析-volatilesynchronized
  • python学习笔记 - ThreadLocal
  • react-native 安卓真机环境搭建
  • 分布式任务队列Celery
  • 分享几个不错的工具
  • 讲清楚之javascript作用域
  • 免费小说阅读小程序
  • 听说你叫Java(二)–Servlet请求
  • 一道面试题引发的“血案”
  • 自制字幕遮挡器
  • 【干货分享】dos命令大全
  • Semaphore
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (NSDate) 时间 (time )比较
  • (二)PySpark3:SparkSQL编程
  • (力扣)循环队列的实现与详解(C语言)
  • (南京观海微电子)——COF介绍
  • (原創) 未来三学期想要修的课 (日記)
  • (正则)提取页面里的img标签
  • (转)可以带来幸福的一本书
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .NET单元测试
  • .NET微信公众号开发-2.0创建自定义菜单
  • @RequestMapping 的作用是什么?
  • @Resource和@Autowired的区别
  • @transaction 提交事务_【读源码】剖析TCCTransaction事务提交实现细节
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [ 手记 ] 关于tomcat开机启动设置问题
  • [Android]一个简单使用Handler做Timer的例子
  • [BZOJ3211]:花神游历各国(小清新线段树)
  • [C++]运行时,如何确保一个对象是只读的
  • [CF226E]Noble Knight's Path