C# 在任务取消时处理CancellationTokenSource的代码是否正确?

C# 在任务取消时处理CancellationTokenSource的代码是否正确?,c#,.net,cancellationtokensource,C#,.net,Cancellationtokensource,我看到前面的代码,我很怀疑: CancellationTokenSource _cts; public void Dispose(); { _cts.Cancel(); _cts.Dispose(); _task.Wait(); //wait for the task to be canceled!? } 取消后直接调用_cts.Dispose()安全吗?如果取消的任务想要成功地等待CancellationToken,那么它不会处理CancellationTokenS

我看到前面的代码,我很怀疑:

CancellationTokenSource _cts;

public void Dispose();
{
    _cts.Cancel();
    _cts.Dispose();
    _task.Wait(); //wait for the task to be canceled!?
}
取消后直接调用_cts.Dispose()安全吗?如果取消的任务想要成功地等待CancellationToken,那么它不会处理CancellationTokenSource的底层资源吗

取消后直接调用_cts.Dispose()安全吗

为了了解这一点,我们需要了解取消
CancellationTokenSource
时会发生什么

当您取消
CancellationTokenSource
时,它会继续调用通过
CancellationToken
注册的任何回调,该回调通过
CancellationToken.Register()
方法保存对其父源的引用

处置CTS时,将尝试从令牌中注销已注册的任何链接回调。如果它当前正在执行,它将等待直到它的委托完成

这意味着,尽管您已经处理了CTS,但它的对象仍然被令牌引用。因此,它仍然没有资格被收集

现在让我们看一下
CancellationToken.IsCancellationRequested

public bool IsCancellationRequested 
{
    get
    {
        return m_source != null && m_source.IsCancellationRequested;
    }
}
这意味着在处理时,检查取消将产生true。这意味着您可以在调用dispose后安全地等待任务完成

作为旁注,如果您(出于某种原因)试图通过令牌的disposed
CancellationTokenSource
传递令牌,您将遇到一个
ObjectDisposedException

编辑:

我想补充两件事。首先,我不建议使用这种方法。它应该适用于某些代码执行路径,但不适用于所有路径
CancellationTokenSource
通常只有在您使用它的
WaitHandle
属性时才应该被释放。否则,由GC来进行清洁是可以的。但是,因为这是一个口味的问题,你可以选择你喜欢的。我当然会建议,只有在您确定任务已遵守取消请求后,才进行处理


根据
WaitHandle
的用法,一旦您处理了它,它就会被处理并清空,因此它将无法访问。

但是IsCancellationRequested不是唯一需要担心的场景,对吗?WaitHandle呢?
WaitHandle
在dispose运行时将关闭。我不确定使用
WaitHandle
是否是常见的用例。我会把它加到我的答案上。@Tim我在我的答案上加了一个重要的编辑。虽然你想做的是可能的,但我绝对不会推荐你。