如何获取取消Task的CancellationToken?附Task转TaskCompletionSource代码
把Task结果同步到TaskCompletionSource的标准实现细节
咱们先看完整的实现代码:
TaskCompletionSource<int> tcs = ...; Task<int> task = ...; task.ContinueWith(t => { if (t.IsCanceled) tcs.TrySetCanceled(new TaskCanceledException(task).CancellationToken); else if (t.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions); else tcs.TrySetResult(task.Result); });
这段代码是异步编程里桥接普通Task和TaskCompletionSource的标准操作,我来拆解下关键细节,尤其是你提到的取消令牌那部分:
- 核心逻辑:通过
ContinueWith注册原Task的完成回调,把原任务的「取消/失败/成功」三种状态,同步到TaskCompletionSource对应的状态上,让外部可以通过tcs.Task获取和原任务一致的异步结果。 - 取消状态的特殊处理:这里特意创建
TaskCanceledException(task)再提取它的CancellationToken传入TrySetCanceled。这么做是因为原Task的CancellationToken可能已经被销毁、或者无法直接访问(比如原任务是第三方库返回的),通过这个异常对象可以拿到和原取消操作绑定的有效令牌。如果直接调用无参的TrySetCanceled(),默认会传入一个空的取消令牌,后续监听tcs.Task的取消状态时,就没法拿到触发取消的原始令牌上下文,会影响错误处理的准确性。 - 异常状态处理:用
task.Exception.InnerExceptions而非直接传task.Exception,是因为Task的异常会被包装在AggregateException里,传入内部异常列表能让tcs抛出的异常更贴合原任务的错误场景,避免额外的聚合包装层。 - 成功状态处理:直接把原Task的结果同步给
tcs即可,逻辑相对简单。
内容的提问来源于stack exchange,提问作者Cory Nelson
相关产品推荐
相关产品推荐

