在需要管理非托管资源或者需要主动销毁重要资源的时候,一般需要实现IDispose接口。为了避免用户忘了主动Dispose,还需要实现析构函数来调用。

DisposeBase做了一些简单的封装。

Nuget包:NewLife.Core

源码:https://github.com/NewLifeX/X/blob/master/NewLife.Core/Common/DisposeBase.cs

视频:https://www.bilibili.com/video/BV1gq4y1g78w

视频:https://www.bilibili.com/video/BV1m8411x7rh

DisposeBase全貌

    public abstract class DisposeBase : IDisposable2
    {
        #region 释放资源
        /// <summary>释放资源</summary>
        public void Dispose()
        {
            Dispose(true);

            // 告诉GC,不要调用析构函数
            GC.SuppressFinalize(this);
        }

        [NonSerialized]
        private Int32 _disposed = 0;
        /// <summary>是否已经释放</summary>
        [XmlIgnore, IgnoreDataMember]
        public Boolean Disposed => _disposed > 0;

        /// <summary>被销毁时触发事件</summary>
        [field: NonSerialized]
        public event EventHandler? OnDisposed;

        /// <summary>释放资源,参数表示是否由Dispose调用。重载时先调用基类方法</summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(Boolean disposing)
        {
            if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0) return;

            if (disposing)
            {
                // 释放托管资源
                //OnDispose(disposing);

                // 告诉GC,不要调用析构函数
                GC.SuppressFinalize(this);
            }

            // 释放非托管资源

            OnDisposed?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>析构函数</summary>
        /// <remarks>
        /// 如果忘记调用Dispose,这里会释放非托管资源
        /// 如果曾经调用过Dispose,因为GC.SuppressFinalize(this),不会再调用该析构函数
        /// </remarks>
        ~DisposeBase() { Dispose(false); }
        #endregion
    }


Dispose(Boolean disposing)

无论Dispose()还是析构函数,都会调用Dispose(Boolean disposing),区别在于前者的disposing。

用户继承DisposeBase后,仅需要重载Dispose(Boolean disposing)即可。

Disposed属性

标识对象是否已经释放


OnDisposed事件

释放时触发


TryDispose 扩展

我们给Object增加了TryDispose扩展方法,如果有实现IDispose接口,则调用其Dispose方法,如果是集合,则递归调用释放。