作为一名C#开发者,你是否遇到过这样的困扰:Timer没有及时释放导致内存泄漏?异步任务无法优雅取消?事件订阅忘记解除导致对象无法回收?这些看似简单的资源管理问题,往往成为项目中的"定时炸弹"。
今天给大家分享一个强大的资源管理模式——ActionDisposable,它能够统一管理各种资源,让你的代码更加健壮,彻底告别资源管理的烦恼。这不是什么高深的理论,而是一个立即可用的实战技巧!
在日常开发中,我们经常需要管理各种资源:
传统做法的问题:
C#// ❌ 传统的问题代码
public class BadExample : IDisposable
{
private Timer _timer;
private CancellationTokenSource _cts;
public BadExample()
{
_timer = new Timer(Callback, null, 1000, 1000);
_cts = new CancellationTokenSource();
SomeEvent += OnSomeEvent; // 容易忘记取消订阅
}
// 经常忘记实现或实现不完整
public void Dispose()
{
_timer?.Dispose(); // 如果忘记这行呢?
_cts?.Cancel(); // 如果这里抛异常呢?
// SomeEvent -= OnSomeEvent; // 经常忘记这行
}
}
ActionDisposable模式通过委托的方式,将资源释放逻辑封装成可组合、可管理的单元。
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppWpfActionDisposable
{
/// <summary>
/// ActionDisposable - 基于委托的资源管理器
/// </summary>
public sealed class ActionDisposable : IDisposable
{
private Action _disposeAction;
private bool _disposed = false;
private readonly object _lock = new object();
public ActionDisposable(Action disposeAction)
{
_disposeAction = disposeAction ?? throw new ArgumentNullException(nameof(disposeAction));
}
public void Dispose()
{
if (_disposed) return;
lock (_lock)
{
if (_disposed) return;
try
{
_disposeAction?.Invoke();
}
finally
{
_disposeAction = null;
_disposed = true;
}
}
}
public bool IsDisposed => _disposed;
/// <summary>
/// 创建一个空的ActionDisposable(什么都不做)
/// </summary>
public static ActionDisposable Empty => new ActionDisposable(() => { });
/// <summary>
/// 组合多个IDisposable对象
/// </summary>
public static ActionDisposable Combine(params IDisposable[] disposables)
{
return new ActionDisposable(() =>
{
foreach (var disposable in disposables)
{
try
{
disposable?.Dispose();
}
catch
{
// 忽略单个释放失败,继续释放其他资源
}
}
});
}
}
}
C#/// <summary>
/// 复合资源管理器 - 统一管理多个资源
/// </summary>
public sealed class CompositeDisposable : IDisposable
{
private readonly List<IDisposable> _disposables = new List<IDisposable>();
private readonly object _lock = new object();
private bool _disposed = false;
public void Add(IDisposable disposable)
{
if (disposable == null) return;
lock (_lock)
{
if (_disposed)
{
disposable.Dispose(); // 如果已释放,立即释放新添加的资源
return;
}
_disposables.Add(disposable);
}
}
public void Remove(IDisposable disposable)
{
lock (_lock) { _disposables.Remove(disposable); }
}
public void Dispose()
{
lock (_lock)
{
if (_disposed) return;
foreach (var disposable in _disposables)
{
try { disposable?.Dispose(); } catch { }
}
_disposables.Clear();
_disposed = true;
}
}
}
C#public class TimerManager : IDisposable
{
private readonly CompositeDisposable _disposables = new CompositeDisposable();
public void StartHeartbeat()
{
var timer = new Timer(HeartbeatCallback, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
// ✅ 使用ActionDisposable管理Timer
new ActionDisposable(() =>
{
timer?.Dispose();
Console.WriteLine("心跳Timer已释放");
}).AddTo(_disposables);
}
public void Dispose() => _disposables.Dispose();
}
// 扩展方法让代码更优雅
public static class DisposableExtensions
{
public static T AddTo<T>(this T disposable, CompositeDisposable composite) where T : IDisposable
{
composite?.Add(disposable);
return disposable;
}
}
C#public class TaskManager : IDisposable
{
private readonly CompositeDisposable _disposables = new CompositeDisposable();
public async Task StartLongRunningTask()
{
var cts = new CancellationTokenSource();
// ✅ 统一管理CancellationTokenSource
var cancellationDisposable = new ActionDisposable(() =>
{
cts?.Cancel();
cts?.Dispose();
Console.WriteLine("任务已取消并清理");
}).AddTo(_disposables);
try
{
await DoLongRunningWork(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("任务被取消");
}
finally
{
_disposables.Remove(cancellationDisposable);
}
}
public void Dispose() => _disposables.Dispose();
}
C#public class EventManager : IDisposable
{
private readonly CompositeDisposable _disposables = new CompositeDisposable();
public void SubscribeToEvents()
{
// ✅ 事件订阅的优雅管理
SomeStaticEvent += OnStaticEvent;
var eventDisposable = new ActionDisposable(() =>
{
SomeStaticEvent -= OnStaticEvent;
Console.WriteLine("事件订阅已取消");
}).AddTo(_disposables);
// PropertyChanged事件订阅
if (someObject is INotifyPropertyChanged notifier)
{
notifier.PropertyChanged += OnPropertyChanged;
new ActionDisposable(() =>
{
notifier.PropertyChanged -= OnPropertyChanged;
}).AddTo(_disposables);
}
}
public void Dispose() => _disposables.Dispose();
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace AppWpfActionDisposable
{
/// <summary>
/// ActionDisposable扩展方法
/// </summary>
public static class ActionDisposableExtensions
{
/// <summary>
/// 添加到复合资源管理器
/// </summary>
public static T AddTo<T>(this T disposable, CompositeDisposable composite) where T : IDisposable
{
composite?.Add(disposable);
return disposable;
}
/// <summary>
/// 延迟释放
/// </summary>
public static ActionDisposable DelayDispose(this IDisposable disposable, TimeSpan delay, Dispatcher dispatcher = null)
{
var timer = new DispatcherTimer(delay, DispatcherPriority.Background,
(s, e) =>
{
((DispatcherTimer)s).Stop();
disposable?.Dispose();
}, dispatcher ?? Dispatcher.CurrentDispatcher);
timer.Start();
return new ActionDisposable(() =>
{
timer.Stop();
disposable?.Dispose();
});
}
}
/// <summary>
/// 复合资源管理器
/// </summary>
public sealed class CompositeDisposable : IDisposable
{
private readonly List<IDisposable> _disposables = new List<IDisposable>();
private readonly object _lock = new object();
private bool _disposed = false;
public void Add(IDisposable disposable)
{
if (disposable == null) return;
lock (_lock)
{
if (_disposed)
{
disposable.Dispose();
return;
}
_disposables.Add(disposable);
}
}
public void Remove(IDisposable disposable)
{
lock (_lock)
{
_disposables.Remove(disposable);
}
}
public void Clear()
{
lock (_lock)
{
foreach (var disposable in _disposables)
{
try { disposable?.Dispose(); } catch { }
}
_disposables.Clear();
}
}
public void Dispose()
{
if (_disposed) return;
lock (_lock)
{
if (_disposed) return;
Clear();
_disposed = true;
}
}
public int Count
{
get
{
lock (_lock)
{
return _disposables.Count;
}
}
}
}
}
C#using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace AppWpfActionDisposable
{
public class MainViewModel : INotifyPropertyChanged, IDisposable
{
private readonly CompositeDisposable _disposables = new CompositeDisposable();
private Timer _heartbeatTimer;
private int _timerCount = 0;
private string _statusMessage = "准备就绪";
private bool _isLoading = false;
public MainViewModel()
{
InitializeCommands();
InitializeTimers();
SetupEventSubscriptions();
}
#region Properties
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
public bool IsLoading
{
get => _isLoading;
set => SetProperty(ref _isLoading, value);
}
public int TimerCount
{
get => _timerCount;
set => SetProperty(ref _timerCount, value);
}
#endregion
#region Commands
public ICommand StartTaskCommand { get; private set; }
public ICommand StopAllCommand { get; private set; }
public ICommand AddResourceCommand { get; private set; }
public ICommand ShowResourceCountCommand { get; private set; }
private void InitializeCommands()
{
StartTaskCommand = new RelayCommand(async () => await StartLongRunningTask());
StopAllCommand = new RelayCommand(() => StopAllTasks());
AddResourceCommand = new RelayCommand(() => AddMockResource());
ShowResourceCountCommand = new RelayCommand(() => ShowResourceCount());
}
#endregion
#region Private Methods
private void InitializeTimers()
{
// 心跳计时器
_heartbeatTimer = new Timer(HeartbeatCallback, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
// 使用ActionDisposable管理Timer
new ActionDisposable(() =>
{
_heartbeatTimer?.Dispose();
StatusMessage = "心跳计时器已停止";
}).AddTo(_disposables);
}
private void SetupEventSubscriptions()
{
// 模拟事件订阅的管理
var eventSubscription = new ActionDisposable(() =>
{
// 这里可以取消事件订阅
StatusMessage = "事件订阅已清理";
});
eventSubscription.AddTo(_disposables);
}
private void HeartbeatCallback(object state)
{
Application.Current?.Dispatcher.Invoke(() =>
{
TimerCount++;
StatusMessage = $"心跳计数: {TimerCount}";
});
}
private async Task StartLongRunningTask()
{
IsLoading = true;
StatusMessage = "正在执行长时间任务...";
var cts = new CancellationTokenSource();
// 使用ActionDisposable管理CancellationTokenSource
var cancellationDisposable = new ActionDisposable(() =>
{
cts?.Cancel();
cts?.Dispose();
StatusMessage = "任务已取消";
IsLoading = false;
}).AddTo(_disposables);
try
{
// 模拟长时间运行的任务
await Task.Run(async () =>
{
for (int i = 0; i < 10; i++)
{
if (cts.Token.IsCancellationRequested)
break;
await Task.Delay(1000, cts.Token);
Application.Current?.Dispatcher.Invoke(() =>
{
StatusMessage = $"任务进度: {(i + 1) * 10}%";
});
}
}, cts.Token);
StatusMessage = "任务已完成";
}
catch (OperationCanceledException)
{
StatusMessage = "任务被用户取消";
}
catch (Exception ex)
{
StatusMessage = $"任务执行出错: {ex.Message}";
}
finally
{
IsLoading = false;
_disposables.Remove(cancellationDisposable);
}
}
private void StopAllTasks()
{
_disposables.Clear();
StatusMessage = "所有任务和资源已清理";
IsLoading = false;
}
private void AddMockResource()
{
// 模拟添加资源
var mockResource = new ActionDisposable(() =>
{
StatusMessage = $"模拟资源已释放 - {DateTime.Now:HH:mm:ss}";
});
mockResource.AddTo(_disposables);
StatusMessage = $"已添加模拟资源,当前资源数: {_disposables.Count}";
}
private void ShowResourceCount()
{
StatusMessage = $"当前管理的资源数量: {_disposables.Count}";
}
#endregion
#region INotifyPropertyChanged & IDisposable
public event PropertyChangedEventHandler PropertyChanged;
private void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!Equals(field, value))
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public void Dispose()
{
_disposables?.Dispose();
_heartbeatTimer?.Dispose();
}
#endregion
}
// 简单的RelayCommand实现
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
public RelayCommand(Action execute, Func<bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
public void Execute(object parameter) => _execute();
}
}

C#// ✅ 好的做法
public class GoodExample : IDisposable
{
private readonly CompositeDisposable _disposables = new CompositeDisposable();
public GoodExample()
{
// 集中管理所有资源
SetupTimer();
SetupEventSubscriptions();
SetupAsyncOperations();
}
private void SetupTimer()
{
var timer = new Timer(Callback, null, 1000, 1000);
new ActionDisposable(() =>
{
try
{
timer?.Dispose();
Console.WriteLine("Timer已安全释放");
}
catch (Exception ex)
{
// 记录日志但不抛出异常
Logger.LogError($"Timer释放失败: {ex.Message}");
}
}).AddTo(_disposables);
}
// 一行代码释放所有资源
public void Dispose() => _disposables?.Dispose();
}
ActionDisposable模式为C#开发者提供了一种优雅的资源管理方案。通过这种模式,我们可以:
这个模式特别适合以下场景:
金句总结:
你在项目中是如何管理资源的?遇到过哪些资源泄漏的坑?欢迎在评论区分享你的经验!
觉得这个技巧有用的话,请转发给更多的.NET同行,让我们一起写出更健壮的C#代码! 🚀
相关信息
通过网盘分享的文件:AppWpfActionDisposable.zip 链接: https://pan.baidu.com/s/1wHK4oJyjJ_MJhlsf9qOg3A?pwd=b41h 提取码: b41h --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!