C# 异步场景下Form关闭后重开报无法访问已释放对象错误
错误原因
- 代码中的
while(true)为无限循环,第二个Form关闭后循环不会终止,仍然会尝试访问已经被释放的Form对象,触发对象已释放异常 - 未做旧任务取消逻辑,多次点击按钮会同时运行多个异步任务,多个任务同时操作同一个Form实例会引发冲突
- 没有对Form实例的生命周期做管理,关闭后的Form实例不会被重置,下次点击会直接访问已释放的旧实例
修复实现
首先在窗体类中定义两个全局字段,用于控制任务取消和持有第二个Form实例:
// 用于取消异步任务的令牌源 private CancellationTokenSource _dataTaskCts; // 第二个展示数据的Form实例,将YourSecondFormType替换为你自己的Form类名 private YourSecondFormType _dataDisplayForm;
修改按钮点击事件,每次点击前先取消上一次运行的任务:
private async void button_click(object sender, EventArgs e) { // 终止上一次的遗留任务 if (_dataTaskCts != null) { _dataTaskCts.Cancel(); _dataTaskCts.Dispose(); } _dataTaskCts = new CancellationTokenSource(); try { await RunDataPushTask(_dataTaskCts.Token); } catch (OperationCanceledException) { // 任务取消为预期行为,无需额外处理 } }
修改异步任务方法,加入取消判断和Form生命周期监听:
private async Task RunDataPushTask(CancellationToken cancelToken) { // 每次打开新建Form实例,不复用已关闭的旧实例 _dataDisplayForm = new YourSecondFormType(); // 监听Form关闭事件,关闭时自动触发任务取消 _dataDisplayForm.FormClosed += (s, args) => { if (!cancelToken.IsCancellationRequested) { _dataTaskCts.Cancel(); } _dataDisplayForm = null; }; _dataDisplayForm.Show(); // 循环中加入取消判断,收到取消信号后立刻终止 while (!cancelToken.IsCancellationRequested) { // 给后台任务传入取消令牌,响应取消信号 await Task.Run(async () => sendData(data1, data2), cancelToken); // 延迟也传入取消令牌,无需等待完整1秒即可终止 await Task.Delay(1000, cancelToken); } }
额外注意事项
- 如果
sendData方法中需要直接操作第二个Form的控件,必须使用控件的Invoke方法避免跨线程操作异常,示例:
private void sendData(object data1, object data2) { // 先判断Form是否已释放,避免访问无效对象 if (_dataDisplayForm?.IsDisposed == false) { // 将TargetTextBox替换为你实际要赋值的控件名 _dataDisplayForm.TargetTextBox.Invoke(new Action(() => { _dataDisplayForm.TargetTextBox.Text = data1.ToString(); // 其他控件赋值操作 })); } }
内容的提问来源于stack exchange,提问作者lollip0o0p
相关产品推荐
相关产品推荐

