我有一个后台任务,正在使用
Task
进行建模,并使用 IAsyncDisposable
停止。
// implementation
public sealed class Worker : IAsyncDisposable
{
private readonly CancellationTokenSource _cts;
private readonly Task _worker;
public Worker()
{
_cts = new CancellationTokenSource();
_worker = DoWork(_cts.Token);
}
public ValueTask DisposeAsync()
{
_cts.Cancel();
_cts.Dispose();
return new ValueTask(_worker);
}
private static async Task DoWork(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
do async work
}
}
}
static async Task CorrectUsage()
{
await using var worker = new Worker();
do more stuff
}
static async Task IncorrectUsage()
{
var worker = new Worker();
do more stuff
}
在正常情况下,这工作得很好,但是,在我看来,如果调用代码不处理worker
Worker
组件被滥用,我希望 GC 在通过
_cts.Cancel()
调用超出范围时终止正在运行的任务。我已经阅读过有关
~Worker()
和
Dispose(bool disposing)
的内容,但我找到的所有文档都指出这些方法专门用于处置非托管资源。
Q1:如何让GC调用_cts.Cancel()
Dispose(bool disposing)
disposing: false
调用它?
_cts.Cancel()
?
像这样:
public sealed class Worker : IAsyncDisposable
{
~Worker()
{
_cts.Cancel();
}
public ValueTask DisposeAsync()
{
_cts.Cancel();
_cts.Dispose();
GC.SuppressFinalize(this);
return new ValueTask(_worker);
}
}
如果
_cts.Cancel()
被释放,则
_cts
会抛出异常。 GC.SuppressFinalize(this)
行确保不会调用
~Worker
终结器,从而防止出现此异常。顺便说明一下,此 DisposeAsync()
实现异步公开
_worker
任务的异常(如果有)。这违背了 C# 社区的集体智慧,根据集体智慧,Dispose
/DisposeAsync
不应该抛出异常。