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