C# 标准的Dispose模式
/// <summary> /// Dispose模式示例 /// </summary> public class Example : IDisposable { /// <summary> /// 标记资源是否已释放 /// </summary> private bool disposed = false; /// <summary> /// 析构函数(终结器) /// 由垃圾回收器在对象被回收前调用,仅用于释放非托管资源,因为此时托管资源可能已被GC回收, /// 即使用户手动调用Dispose也可能存在当前对象被其他地方引用导致不能正常释放的情况,更何况还有可能干脆就忘记手动调用了,为了安全起见,因此要在析构函数中调用Dispose(bool disposing)做最后的保障 /// </summary> ~Example() { // 仅释放非托管资源 Dispose(false); } /// <summary> /// 实现IDisposable接口的显式释放方法 /// 供用户代码主动调用释放资源 /// </summary> public void Dispose() { // 释放托管和非托管资源 Dispose(true); // 阻止GC调用终结器,因为资源已被显式释放 GC.SuppressFinalize(this); } /// <summary> /// 释放资源的核心实现, /// 之所以提供这样一个受保护的虚方法,是为了考虑到这个类型会被其他类继承的情况。如果类型存在一个子类,子类也许会实现自己的Dispose模式。受保护的虚方法用来提醒子类必须在实现自己的清理方法的时候注意到父类的清理工作,即子类需要在自己的释放方法中调用base.Dispose方法 /// </summary> /// <param name="disposing"> /// true: 由Dispose()方法调用(显式释放),需同时释放托管和非托管资源 /// false: 由终结器调用(隐式释放),仅释放非托管资源 /// </param> protected virtual void Dispose(bool disposing) { // 防止重复释放 if (!disposed) { if (disposing) { // 释放托管资源(如IDisposable对象) // 示例: managedResource?.Dispose(); } // 释放非托管资源(如文件句柄、数据库连接等) // 示例: CloseHandle(nativeHandle); nativeHandle = IntPtr.Zero; // 标记为已释放 disposed = true; } } }
除非类直接管理非托管资源,否则没必要整这么麻烦,即使引用了Socket这种封装了非托管资源的类,也没必要整这么繁琐,完全可以简单粗暴的这样写,
public class Example : IDisposable { Socket socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); /// <summary> /// 记得手动调用Dispose,或者使用using,即使忘记调用了,也会GC,但是GC的执行时机是不确定的,可能导致资源长时间无法释放 /// </summary> public void Dispose() { socket.Dispose(); socket = null!; GC.SuppressFinalize(this); } }

浙公网安备 33010602011771号