c#中接口的使用方法图解_深入理解C#中的IDisposable接口

本文深入探讨了C#中如何正确释放非托管资源,特别是使用IDisposable接口的重要性。解释了如何实现Dispose模式,析构方法(终结器)的作用,以及为何需要提供一个虚Dispose方法。此外,文章还讨论了何时需要将对象置为null,以及在处理静态字段时的内存管理策略。
摘要由CSDN通过智能技术生成

在开始之前,我们需要明确什么是C#(或者说.NET)中的资源,打码的时候我们经常说释放资源,那么到底什么是资源,简单来讲,C#中的每一种类型都是一种资源,而资源又分为托管资源和非托管资源,那这又是什么?!

托管资源:由CLR管理分配和释放的资源,也就是我们直接new出来的对象;

非托管资源:不受CLR控制的资源,也就是不属于.NET本身的功能,往往是通过调用跨平台程序集(如C++)或者操作系统提供的一些接口,比如Windows内核对象、文件操作、数据库连接、socket、Win32API、网络等。

我们下文讨论的,主要也就是非托管资源的释放,而托管资源.NET的垃圾回收已经帮我们完成了。其实非托管资源有部分.NET的垃圾回收也帮我们实现了,那么如果要让.NET垃圾回收帮我们释放非托管资源,该如何去实现。

如何正确的显式释放资源

假设我们要使用FileStream,我们通常的做法是将其using起来,或者是更老式的try…catch…finally…这种做法,因为它的实现调用了非托管资源,所以我们必须用完之后要去显式释放它,如果不去释放它,那么可能就会造成内存泄漏。

这听上去貌似很简单,但我们编码的时候可能很多时候会忽略掉释放资源这个问题,.NET的垃圾回收又如何帮我们释放非托管资源,接下来我们一探究竟吧,一个标准的释放非托管资源的类应该去实现IDisposable接口:

public class MyClass:IDisposable
{
    
    /// <summary>执行与释放或重置非托管资源关联的应用程序定义的任务。</summary>
    public void Dispose()
    {
    
    }
}

我们实例化的时候就可以将这个类using起来:

using(var mc = new MyClass())
{
    
}

看上去很简单嘛,但是,要是就这么简单的话,也没有这篇文章的必要了。如果要实现IDisposable接口,我们其实应该这样做:

  1. 实现Dispose方法;
  2. 提取一个受保护的Dispose虚方法,在该方法中实现具体的释放资源的逻辑;
  3. 添加析构函数;
  4. 添加一个私有的bool类型的字段,作为释放资源的标记

接下来,我们来实现这样的一个Dispose模式:

public class MyClass : IDisposable
{
    
    /// <summary>
    /// 模拟一个非托管资源
    /// </summary>
    private IntPtr NativeResource {
     get; set; } = Marshal.AllocHGlobal(100);
    /// <summary>
    /// 模拟一个托管资源
    /// </summary>
    public Random ManagedResource {
     get; set; } = new Random();
    /// <summary>
    /// 释放标记
    /// </summary>
    private bool disposed;
    /// <summary>
    /// 为了防止忘记显式的调用Dispose方法
    /// </summary>
    ~MyClass()
    {
    
        //必须为false
        Dispose(false);
    }
    /// <summary>执行与释放或重置非托管资源关联的应用程序定义的任务。</summary>
    public void Dispose()
    {
    
        //必须为true
        Dispose(true);
        //通知垃圾回收器不再调用终结器
        GC.SuppressFinalize(this);
    }
    /// <summary>
    /// 非必需的,只是为了更符合其他语言的规范,如C++、java
    /// </summary>
    public void Close()
    {
    
        Dispose();
    }
    /// <summary>
    /// 非密封类可重写的Dispose方法,方便子类继承时可重写
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
    
        if (disposed)
        {
    
            return;
        }
        //清理托管资源
        if (disposing)
        {
    
            if (ManagedResource != null)
            {
    
                ManagedResource = null;
            }
        }
        //清理非托管资源
        if (NativeResource != IntPtr.Zero)
        {
    
            Marshal.FreeHGlobal(
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值