在需要管理非托管资源或者需要主动销毁重要资源的时候,一般需要实现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方法,如果是集合,则递归调用释放。