避免cancellationtokensource的objectdisposedexception的核心是精准管理其生命周期,确保在所有依赖它的操作完成前不被提前释放;2. 局部使用时应采用using语句,确保using块结束时自动dispose;3. 跨方法传递时只传递cancellationtoken而非cancellationtokensource,防止外部误调用dispose;4. 对于长期存在或共享的cancellationtokensource,应在所属对象的dispose方法中统一释放;5. 使用createlinkedtokensource创建的组合令牌源也需用using管理或在适当时机手动dispose;6. 只有当所有使用该令牌的任务已完成、被取消或明确不再需要时,才可安全调用dispose,避免多线程竞态导致异常。只要遵循“谁创建谁负责、及时释放、不传递源对象”的原则,就能有效杜绝此类异常的发生。

CancellationTokenSource
ObjectDisposedException
CancellationTokenSource
CancellationToken
CancellationTokenSource
要彻底避免
CancellationTokenSource
ObjectDisposedException
IDisposable
就地取材,立即销毁:using
CancellationTokenSource
using
Dispose
public async Task DoSomethingCancellable()
{
// 假设这个操作最多运行5秒
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
{
try
{
// 把token传给需要支持取消的操作
await Task.Delay(TimeSpan.FromSeconds(10), cts.Token);
Console.WriteLine("操作完成。");
}
catch (OperationCanceledException)
{
Console.WriteLine("操作被取消了!");
}
// using块结束时,cts会自动Dispose,非常省心。
}
}这种方式几乎能覆盖大部分简单的场景,因为它强制了资源的及时释放,并且避免了手动管理
Dispose
跨越边界,传递Token
Source
CancellationTokenSource
Token
cts.Token
CancellationTokenSource
CancellationTokenSource
CancellationToken
CancellationTokenSource
Dispose()
ObjectDisposedException
// 错误示范:把CancellationTokenSource传了出去
public async Task ProcessData(CancellationTokenSource cts)
{
// 某个不负责任的开发者可能在这里调用了cts.Dispose()
// 导致上游或其它地方再用这个cts时出问题
// cts.Dispose(); // 比如这里不小心写了这句
await Task.Delay(1000, cts.Token);
}
// 正确示范:只传递CancellationToken
public async Task ProcessDataSafe(CancellationToken token)
{
// token是只读的,你无法Dispose它,也无法通过它来触发取消(除非它是一个可取消的token)
// 这样就保证了CancellationTokenSource的生命周期由它的拥有者管理
await Task.Delay(1000, token);
}通过这种方式,
CancellationTokenSource
Dispose
长期存在或共享的CancellationTokenSource
CancellationTokenSource
using
Dispose
IHostApplicationLifetime.ApplicationStopped
Dispose
// 假设这是一个服务,它有一个全局的CancellationTokenSource
public class MyBackgroundService : BackgroundService, IDisposable
{
private readonly CancellationTokenSource _appCts = new CancellationTokenSource();
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// 组合应用停止令牌和我们自己的令牌
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
stoppingToken, _appCts.Token);
try
{
await DoWorkAsync(linkedCts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("后台服务工作被取消了。");
}
}
public void StopMyWork()
{
// 外部调用这个方法来取消服务内部的工作
_appCts.Cancel();
}
public void Dispose()
{
// 确保在服务实例被销毁时,CancellationTokenSource也被Dispose
// 避免资源泄露,比如内部的WaitHandle
_appCts.Dispose();
}
}这里,
_appCts
Dispose
IDisposable
CancellationTokenSource
这个问题问得很好,毕竟不是所有对象都需要显式
Dispose
CancellationTokenSource
Dispose
WaitHandle
WaitHandle
Dispose
CancellationTokenSource
虽然在很多简单场景下,如果你不
Dispose
Dispose
CancellationTokenSource
在异步编程中,管理
CancellationTokenSource
一个核心的考量是:谁拥有CancellationTokenSource
Dispose
方法内部的局部生命周期: 这是最常见的,也是最简单的。如果一个
CancellationTokenSource
using
CancellationTokenSource
组件或服务层面的生命周期: 当
CancellationTokenSource
CancellationTokenSource
Dispose
IHostedService
StopAsync
Dispose
CancellationTokenSource
组合取消令牌:CancellationTokenSource.CreateLinkedTokenSource
CreateLinkedTokenSource
CancellationToken
CreateLinkedTokenSource
CancellationTokenSource
Dispose
// 场景:一个长时间运行的报告生成任务,可以被用户取消,也可以在应用关闭时自动取消
public async Task GenerateReportAsync(CancellationToken userCancellationToken)
{
// 获取应用程序的停止令牌(比如来自IHostApplicationLifetime)
var appStoppingToken = _hostApplicationLifetime.ApplicationStopping;
// 组合两个令牌:只要其中一个被取消,任务就取消
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
userCancellationToken, appStoppingToken))
{
try
{
Console.WriteLine("开始生成报告...");
await Task.Delay(TimeSpan.FromSeconds(30), linkedCts.Token); // 模拟长时间操作
Console.WriteLine("报告生成完成。");
}
catch (OperationCanceledException)
{
Console.WriteLine("报告生成被取消了。");
}
// linkedCts在这里会被Dispose
}
}这里,
linkedCts
GenerateReportAsync
using
CancellationTokenSource
这是一个核心问题,也是最容易出错的地方。调用
CancellationTokenSource
Dispose
CancellationToken
操作完成或取消之后: 这是最理想的时机。如果你有一个
Task
CancellationToken
Task
RanToCompletion
Canceled
Faulted
Dispose
CancellationTokenSource
var cts = new CancellationTokenSource();
var longRunningTask = Task.Run(async () =>
{
try
{
await Task.Delay(5000, cts.Token); // 模拟一个耗时操作
Console.WriteLine("任务完成。");
}
catch (OperationCanceledException)
{
Console.WriteLine("任务被取消。");
}
});
// 假设在某个时刻我们决定取消它
cts.Cancel();
// 等待任务结束,无论它是完成还是被取消
await longRunningTask;
// 任务结束后,再Dispose CancellationTokenSource
cts.Dispose(); // 现在是安全的如果你在
longRunningTask
cts.Dispose()
Task.Delay
Dispose
cts.Token
ObjectDisposedException
当令牌不再被任何地方观察时: 如果你通过
token.Register()
避免竞态条件: 在多线程或并发环境中,一个线程可能正在使用
CancellationToken
Dispose
ObjectDisposedException
总的来说,处理
CancellationTokenSource
Dispose
using
ObjectDisposedException
以上就是CancellationTokenSource的ObjectDisposedException怎么避免?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号